privateSLNodegetNode(inti){
SLNodep=head.getNext();
for(;i>0;i--)
p=p.getNext();
returnp;
}
//返回线性表的大小,即数据元素的个数。
publicintgetSize(){
returnsize;
}
//如果线性表为空返回true,否则返回false。
publicbooleanisEmpty(){
returnsize==0;
}
//判断线性表是否包含数据元素e
publicbooleancontains(Objecte){
SLNodep=head.getNext();
while(p!
=null){
if(p.getData()==e))returntrue;
elsep=p.getNext();
}returnfalse;
}
//将数据元素e插入到线性表中i号位置
publicvoidinsert(inti,Objecte)throwsOutOfBoundaryException{
if(i<0||i>size)
thrownewOutOfBoundaryException("错误,指定的插入序号越界。
");
SLNodep=getPreNode(i);
SLNodeq=newSLNode(e,p.getNext());
p.setNext(q);
size++;
return;
}
//删除线性表中序号为i的元素,并返回之
publicObjectremove(inti)throwsOutOfBoundaryException{
if(i<0||i>=size)
thrownewOutOfBoundaryException("错误,指定的删除序号越界。
");
SLNodep=getPreNode(i);
Objectobj=p.getNext().getData();
p.setNext(p.getNext().getNext());
size--;
returnobj;
}
//删除线性表中第一个与e相同的元素
publicbooleanremove(Objecte){
SLNodep=getPreNode(e);
if(p!
=null){
p.setNext(p.getNext().getNext());
size--;
returntrue;
}
returnfalse;
}
//替换线性表中序号为i的数据元素为e,返回原数据元素
publicObjectreplace(inti,Objecte)throwsOutOfBoundaryException{
if(i<0||i>=size)
thrownewOutOfBoundaryException("错误,指定的序号越界。
");
SLNodep=getNode(i);
Objectobj=p.getData();
p.setData(e);
returnobj;
}
//返回线性表中序号为i的数据元素
publicObjectget(inti)throwsOutOfBoundaryException{
if(i<0||i>=size)
thrownewOutOfBoundaryException("错误,指定的序号越界。
");
SLNodep=getNode(i);
returnp.getData();
}
}
7.循环链表:
是一种首尾相连的链表。
特点是无需增加存储量,仅对表的链接方式修改使表的处理灵活方便。
8.空循环链表仅由一个自成循环的头结点表示。
9.很多时候表的操作是在表的首尾位置上进行,此时头指针表示的单循环链表就显的不够方便,改用尾指针rear来表示单循环链表。
用头指针表示的单循环链表查找开始结点的时间是O
(1),查找尾结点的时间是O(n);用尾指针表示的单循环链表查找开始结点和尾结点的时间都是O
(1)。
10.在结点中增加一个指针域,prior|data|next。
形成的链表中有两条不同方向的链称为双链表。
publicclassDLNodeimplementsNode{
privateObjectelement;
privateDLNodepre;
privateDLNodenext;
publicDLNode(Objectele,DLNodepre,DLNodenext){
this.element=ele;
this.pre=pre;
this.next=next;
}
publicDLNodegetNext(){
returnnext;
}
publicvoidsetNext(DLNodenext){
this.next=next;
}
publicDLNodegetPre(){
returnpre;
}
publicvoidsetPre(DLNodepre){
this.pre=pre;
}
publicObjectgetData(){
returnelement;
}
publicvoidsetData(Objectobj){
element=obj;
}
}
publicclassLinkedListDLNodeimplementsLinkedList{
privateintsize;//规模
privateDLNodehead;//头结点,哑元结点
privateDLNodetail;//尾结点,哑元结点
publicLinkedListDLNode(){
size=0;
head=newDLNode();//构建只有头尾结点的链表
tail=newDLNode();
head.setNext(tail);
tail.setPre(head);
}
//辅助方法,判断结点p是否合法,如合法转换为DLNode
protectedDLNodecheckPosition(Nodep)throwsInvalidNodeException{
if(p==null)
thrownewInvalidNodeException("错误:
p为空。
");
if(p==head)
thrownewInvalidNodeException("错误:
p指向头节点,非法。
");
if(p==tail)
thrownewInvalidNodeException("错误:
p指向尾结点,非法。
");
DLNodenode=(DLNode)p;
returnnode;
}
//查询链接表当前的规模
publicintgetSize(){
returnsize;
}
//判断链接表是否为空
publicbooleanisEmpty(){
returnsize==0;
}
//返回第一个结点
publicNodefirst()throwsOutOfBoundaryException{
if(isEmpty())
thrownewOutOfBoundaryException("错误:
链接表为空。
");
returnhead.getNext();
}
//返回最后一结点
publicNodelast()throwsOutOfBoundaryException{
if(isEmpty())
thrownewOutOfBoundaryException("错误:
链接表为空。
");
returntail.getPre();
}
//返回p之后的结点
publicNodegetNext(Nodep)throwsInvalidNodeException,OutOfBoundaryException{
DLNodenode=checkPosition(p);
node=node.getNext();
if(node==tail)
thrownewOutOfBoundaryException("错误:
已经是链接表尾端。
");
returnnode;
}
//返回p之前的结点
publicNodegetPre(Nodep)throwsInvalidNodeException,OutOfBoundaryException{
DLNodenode=checkPosition(p);
node=node.getPre();
if(node==head)
thrownewOutOfBoundaryException("错误:
已经是链接表前端。
");
returnnode;
}
//将e作为第一个元素插入链接表
publicNodeinsertFirst(Objecte){
DLNodenode=newDLNode(e,head,head.getNext());
head.getNext().setPre(node);
head.setNext(node);
size++;
returnnode;
}
//将e作为最后一个元素插入列表,并返回e所在结点
publicNodeinsertLast(Objecte){
DLNodenode=newDLNode(e,tail.getPre(),tail);
tail.getPre().setNext(node);
tail.setPre(node);
size++;
returnnode;
}
//删除给定位置处的元素,并返回之
publicObjectremove(Nodep)throwsInvalidNodeException{
DLNodenode=checkPosition(p);
Objectobj=node.getData();
node.getPre().setNext(node.getNext());
node.getNext().setPre(node.getPre());
size--;
returnobj;
}
//删除首元素,并返回之
publicObjectremoveFirst()throwsOutOfBoundaryException{
returnremove(head.getNext());
}
//删除末元素,并返回之
publicObjectremoveLast()throwsOutOfBoundaryException{
returnremove(tail.getPre());
}
//将处于给定位置的元素替换为新元素,并返回被替换的元素
publicObjectreplace(Nodep,Objecte)throwsInvalidNodeException{
DLNodenode=checkPosition(p);
Objectobj=node.getData();
node.setData(e);
returnobj;
}
}
11.顺序表和链表的比较
1) 基于空间的考虑:
顺序表的存储空间是静态分配的,链表的存储空间是动态分配的。
顺序表的存储密度比链表大。
因此,在线性表长度变化不大,易于事先确定时,宜采用顺序表作为存储结构。
2) 基于时间的考虑:
顺序表是随机存取结构,若线性表的操作主要是查找,很少有插入、删除操作时,宜用顺序表结构。
对频繁进行插入、删除操作的线性表宜采用链表。
若操作主要发生在表的首尾时采用尾指针表示的单循环链表。
12.存储密度=(结点数据本身所占的存储量)/(整个结点结构所占的存储总量)
存储密度:
顺序表=1,链