循环链表
将单链表中终端节点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表
循环链表和单链表主要差异:循环的判断条件上,单链表是判断p->next是否为空,循环是判断p->next不等于头结点
若想要用O(1)的时间由链表指针访问到最后一个结点,则不用头指针,而是用指向终端结点的尾指针来表示循环链表
举例,要将两个循环链表合并成一个表时,有了尾指针就十分简单
下面的两个循环链表,尾指针分别是rearA rearB
p = rearA->next; //保存A表的头结点
rearA->next = rearB->next->next; //将本是指向B表的第一个结点(不是头结点)赋值给rearA->next
rearB->next = p; //将原是A表的头结点赋值给rearB->next
free(p); //释放p
要想将他们合并,只需如下操作
双向链表
双向链表是在单链表的每个结点中,在设置一个指向其前驱结点的指针域
//线性表的双向链表存储结构
typedef struct DulNode
{
ElemTyoe data;
struct DulNode *prior; //直接前驱指针
struct DulNode *next; //直接后驱指针
}DulNode, *DuLinkList;
双向链表的前驱的后继是本身;
p->next->prior = p->prior->next
双向链表是单链表中扩展出来结构,所以很多操作和单链表相同,比如求长度的ListLength,查找元素的GetElem,获得元素的LocateElem等,
这些操作只要涉及一个方向的指针即可。
双向链表的插入
顺序很重要(先搞定s的前继和后继,再搞定后结点的前驱,最后搞定前结点的后继) ,如图说示
s->prior = p; //把p赋给s的前驱
s->next = p->next; //把p->next赋值给s的后继
p->next->prior = s; //把s赋值给p->next的前驱
p->next = s; //把s赋值给p的后继
双向链表的删除
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
双线链表,对于单链表来说,多了两个指针,更复杂一些,空间占用略多一些,但由于良好的对称性,
有效提高了算法的时间性能。典型的,以占用空间来换时间。