循环链表
循环链表 表中最后一个结点的指针域指向头结点,整个链表形成一个环。所以,从表中任一结点出发均可找到表中其他结点。
- 循环单链表的操作和单链表基本一致
- 区别当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同
(1)单链表中判别条件为 p!= NULL 或 p->next!= NULL
(2)循环链表中判别条件为 p!= L 或 p->next!=L
非空表
空表
判断空链表的条件是head==head->next;
(在此可回顾下单链表https://blog.youkuaiyun.com/qq_45947684/article/details/104078817)
- 在某些情况下,若在循环链表中设立尾指针而不设头指针,可使一些操作简单化。
例:将两个线性表合并成一个表时,仅需将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。
p=B->next->next;
B->next=A->next;
A->next=p;
此操作时间复杂度为O(l)
双向链表
在单链表中查找直接后继结点的执行时间为O(l),查找直接前驱的执行时间为O(n)。为弥补此缺点则用双向链表。
双向链表的结点中有两个指针域,一个指向直接后继,另一个指向直接前继。
typedef struct DuLNode
{
ELemType data; //数据域
struct DuLNode *prior; //指向直接前驱
struct DuLNode *next; //指向直接后驱
}DuLNode,*DuLinkList;
-
双向循环链表
-
空双向循环链表
-
非空双向链表
d->next->prior=d->prior->next=d
(d为DuLinkList型变量)
- 插入
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e)
{ //在带头结点的双向链表L中第 i个位置之前插入元素e
if(!(p=GetElem_DuL(L,i))) //在L中确定第 i个元素的位置指针p
return ERROR; //p为NULL时,第 i个元素不存在
s=new DoLNode; //生成新结点*s
s->data=e; //将结点*s数据域置为e
s->prior=p->prior; //将结点*s插入L中(1)
p->prior->next=s; //(2)
s->next=p; //(3)
p->prior=s; //(4)
return OK;
}
-
时间复杂度为O(n)
-
删除
Status ListDelete_DuL(DuLinkList &L,int i)
{ //删除带头结点的双向链表L中的第 i个元素
if(!(p=GetElem_DuL(L,i))) //在L中确定第 i个元素的位置指针p
return ERROR; //p为NULL时,第 i个元素不存在
p->prior->next=p->next; //修改被删结点的前驱结点的后继指针(1)
p->next->prior=p->prior; //修改被删结点的后继结点的前驱指针(2)
delete p; //释放被删结点的空间
return OK;
}
- 时间复杂度为O(n)