开篇口水话:
无论是学习单链表、还是循环、双向链表,
掌握 节点的“增、删
”操作很重要,难的就是指针域的指来指去
不能乱序
循环链表
1.单链循环链表,如此定义
- 和单链表,大同小异
- 也就是在单链表基础上,最后一个结点的指针域,指向头结点(或者第一个结点)
2.于是乎,循环链表可以
从任意节点出发,都可以遍历其他结点
但,不能死循环。
那么就让循环单链表,结束循环判别条件:p->next !=L
/ p!=L
类似的,还有多重链的循环链表…
3.单链循环链表的合并
比如有A、B两个单链循环链表(设A、B是指向“最后一个结点”的指针)
那么 A->next
就是头结点。同理,B表也有一个头结点
二者合并,需要去掉其中一个头结点。
参考code如下:
p = B->next -> next;
B->next = A->next;
A->next = p;
时间复杂度O(1)
双向链表
1.顾名思义
两个方向都link,
所以每个结点 除了 Data Field
还有 Prior Field 直接前驱
、Next Field 直接后继
结点的结构体定义
typedef struct DuLNode{
ElemType data;
struct DuLNode *next;
struct DuLNode *prior;
}DuLNode, *DuLinkList;
2.看图说话
L = L->next
设d是指向任意结点的指针,
那么, d = d->next->prior = d->prior->next
3.双向链表的“牵线”(增删结点,指针指向)
图是这样的:
难的是,考虑这四个步骤,前后顺序。
第四步,放在最后,其他步骤可以随意。 自己好好感受吧~
代码如下
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){ //双向链表的插入
//在带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1<=i<=表长+1
DuLNode *s,*p;
if(!(p=GetElemP_DuL(L,i))) //在L中确定第i个元素的位置指针p
return ERROR; //p为NULL时,第i个元素不存在
s=new DuLNode; //生成新结点s
s->data=e; //将结点s数据置为e
s->prior=p->prior; //将结点s插入L中,需要修改4个指针域
p->prior->next=s;
s->next=p;
p->prior=s;
return OK;
}
类似的双向链表的删除
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){ //双向链表的删除
//删除带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1<=i<=表长
DuLNode *p;
if(!(p=GetElemP_DuL(L,i))) //在L中确定第i个元素的位置指针p
return ERROR; //p为NULL时,第i个元素不存在
e=p->data; //保存被删结点的数据域
p->prior->next=p->next; //修改被删结点的前驱结点的后继指针
p->next->prior=p->prior; //修改被删结点的后继结点的前驱指针
delete p; //释放被删结点的空间
return OK;
}