循环链表
- 定义:循环链表是一种头尾相接的链表(即:表中最后一个结点的指针域指向头结点,整个链表形成一个环)。
- 优点:从表中任一结点出发均可找到表中其他结点。
- 注意:
由于循环链表中没有NULL指针,故涉及遍历操作时,其终止条件就不再像非循环链表那样判断p或p->next 是否为空,而是判断它们是否等于头指针。 - 循环条件:
//单链表
p!=NULL
p->next!=NULL
//单循环链表
p!=L
p->next!=L
- 头指针表示单循环链表
表的操作常常在表的首位位置上进行
- 尾指针表示单循环链表
- 带尾指针循环链表的合并
//假设Ta,Tb都是非空的单循环链表
LinkList Connect(LinkList Ta,LinkList Tb){
p=Ta->next; //p存表头结点
Ta->next=Tb->next->next; //Tb表头连结点Ta表尾
delete Tb->next; //释放Tb表头结点
Tb->next=p; //修改指针
return Tb;
}
时间复杂度:O(1)
为什么要讨论双向链表:
单链表的结点:
① 有指示后继的指针域,找后继结点方便;即查找某结点的后继结点的执行时间为a(1)。
② 无指示前驱的指针域,找前驱结点难:从表头出发查找。即:查找某结点的前驱结点的执行时间为a(n)。
可用双向链表来克服单链表的这种缺点。
双向链表
-
定义:双向链表在单链表的每个结点里再增加一个指向其直接前驱的指针域prior ,这样链表中就形成了有两个方向不同的链,故称为双向链表。
-
双向链表的结构定义:
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;
双向循环链表
- 描述:双向循环链表和单链的循环表类似,双向链表也可以有循环表。 让头结点的前驱指针指向链表的最后一个结点;
让最后一个结点的后继指针指向头结点。
- 双向链表结构的对称性
在双向链表中有些操作(如: (ListLength、GetElem等),因仅涉及一个方向的指针,故它们的算法与线性链表的相同。但在插入、删除时,则需同时修改两个方向上的指针,两者的操作的时间复杂度均为O(n)。
p->prior->next=p=p->next->prior
双向链表基本操作的实现
在双向链表中有些操作(如: (ListLength、GetElem等),因仅涉及一个方向的指针,故它们的算法与线性链表的相同。但在插入、删除时,则需同时修改两个方向上的指针,所以有所不同。
1、双向链表的插入
void ListInsert_DuL(DuLinkList &L,int i,ElemType e){
if(!(p=GetElemP_DuL(L,i)))
return error;
s=new DuLDode;
s->data=e;
s->prior=p->prior;//a结点成为x结点的前驱结点
p->prior->next=s;//a结点成为x结点的后继结点
s->next=p;//x结点成为b结点的前驱结点
p->prior=s;//x结点成为b结点的后继结点
return ok;
} //ListInsert_DuL
时间复杂度:O(n)
2、双向链表的删除
void ListDelete_DuL(DuLink &L,int i,ElemType &e){
if(!(p=GetElemP_DuL(L,i)))
return error;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return ok;
} //ListDelete_DuL
时间复杂度:O(n)
ending~~~
有什么问题欢迎留言噢