本篇文章参考的是《大话数据结构》,感谢作者程杰先生。
一:循环链表:
将单链表中终端节点的指针端由空指针改为指向头结点,就使整个单链表形成了一个环,
这种头尾相接的单链表称为单循环链表,简称循环链表(circular linked list)。
图示:
二: 将下面两个单循环链表合并:
过程如下:
p = rearA->next; // 保存A表的头结点,即①
rearA->next = rearB->next->next; //将本是指向B表的第一个节点(不是头结点),赋值给 rearA->next,即②
rearB->next = p; //将原A表的头结点赋值给 rearB->next,即③
free(p); //释放p
三:双向链表(double linked list):
在单链表的每个节点中,再设置一个指向其前驱结点的指针。所以在双向链表中的结点都有两个指针域,
一个指向直接后继,一个指向直接前驱。
/*线性表的双向链表存储结构*/
typedef struct DulNode
{
ElemType data;
struct DuLNode *prior; /*直接前驱指针*/
struct DuLNode *next; /*直接后继指针*/
} DulNode, *DuLinkList;
四:非空的循环的带头结点的双向链表如下所示:
就像人生一样,想享乐就得先努力,欲收获就得付出代价。
双向链表既然比单链表多了反向遍历查找等数据结构,就得付出一些代价,
在插入和删除时,需要改变两个指针变量。
五: 双链表的插入:
插入操作并不复杂,但是顺序很重要,绝对不能写错了。
假设存储元素e的结点为s,要实现将结点s插入到结点p和p->next之间需要如下几步:
总共分四步:
s->prior = p; //把p赋值给s的前驱,如图中1
s->next = p->next; //把p->next赋值给s的后继,如图中2
p->next->prior = s; //把s赋值给p->next的前驱,如图中3
p-next = s; //把s赋值给p的后继,如图中4
技巧1:赋值的顺序(双臂伸缩法)
1.展开左手臂;
2.展开右手臂;
3.收回右手臂;
4.收回左手臂;
刚好对应上图的4条箭头指向。
技巧2:每一步的赋值(看箭头指向)
A -----------------------------------------------------------------> B
A的前驱/后继(取决于箭头从A的那个位置开始) = B(直接写该结点的标识);
六:双链表的删除:
要删除结点p,只需要如下两步:
总共分三步:
p->prior->next = p->next; //把p->next赋值给p->prior的后继,如图1
p->next->prior = p->prior; //把p->prior赋值给p->next的前驱,如图2
free(p); //释放节点p
注:
1.删除的顺序是先上后下(箭头);
2.对于删除来说技巧2同样适用;