DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。

上接:DS第三篇(中):线性表之链表——单链表

开篇口水话:

无论是学习单链表、还是循环、双向链表,
掌握 节点的“增、删”操作很重要,难的就是指针域的指来指去
不能乱序

循环链表

1.单链循环链表,如此定义

  • 和单链表,大同小异
  • 也就是在单链表基础上,最后一个结点的指针域,指向头结点(或者第一个结点)

DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第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 直接后继
DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第2张图片
结点的结构体定义

typedef struct DuLNode{
	ElemType data;
	struct DuLNode *next;
	struct DuLNode *prior;
}DuLNode, *DuLinkList;   

2.看图说话

DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第3张图片

L = L->next


DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第4张图片

设d是指向任意结点的指针,
那么, d = d->next->prior = d->prior->next

3.双向链表的“牵线”(增删结点,指针指向)

图是这样的:
DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第5张图片
DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第6张图片

难的是,考虑这四个步骤,前后顺序
第四步,放在最后,其他步骤可以随意。 自己好好感受吧~

代码如下

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;
}	

顺序表和链表的比较

DS第三篇(下):线性表之链表——循环链表、双向链表、顺序表和链表的比较。_第7张图片

你可能感兴趣的:(链表,数据结构,指针,单链表,算法)