数据结构之双向链表-1

简介: 数据结构之双向链表

引言

数据结构之路在链表章节,前面介绍过单链表,今天我们来介绍最复杂的链表——双向链表(Double Linked List)


链表的分类

88f4fb01fe132b0b8570acd4c2e8504d_c643302dbf3c4144a911c55d355d0b5b.png


虽然有这么多的链表的结构,但是我们实际中 最常用 还是 两种结构 : 单链表 和 双向带头循环链表

1. 无头单向非循环链表 :结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的 子结构 ,如 哈希桶、图的邻接表 等等。另外这种结构在 笔试面试 中出现很多。

2. 带头双向循环链表 :结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势, 实现 反而 简单 了,后面我们代码实现了就知道了。

前面我们讲的单链表,就是无头单向非循环链表,而现在讲的双向链表,就是带头双向循环链表。


双向链表的结构


e474b32f161318b1140a2198a3cc3ebe_69a62e21912d4e02aa39b5f1dffef38e.png

注意: 这里的 “带头” 跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严谨,但是为了同学们更好的理解就直接称为单链表的头节点。

带头链表里的头节点,实际为“哨兵位” ,哨兵位节点 不存储任何有效元素 ,只是站在这里“放哨的”

“哨兵位”存在的意义:

遍历循环链表避免死循环


双向链表的实现

定义

与单链表不同,一个节点里有两个指针,分别指向前节点和后节点,实现双向


9f78a42af47045b199a61b8657a35708.png


创建新节点

创建新节点与单链表大致相同,抽离成函数方便创建节点


43f42bd3fd5647cd84838aedb0af1435.png


初始化

双向链表与单链表很大区别,就是在于初始化,创建哨兵位,而哨兵位不存储有效数据,所有这里存入-1,并让prev和next指针都指向自身


33a30efd520243a2afdcb38ece25a447.png


打印

首先assert断言,因为phead指向哨兵位,一定不为空,其次因为双向循环链表里没有NULL,所有停止条件就看哨兵位,当cur指针的下一个为哨兵位时,就代表走到尾部了


53a6c987b7f14a2c8c057b3032c7f4bb.png


尾插

双向循环结构在空链表插入时,带来了极大的便利。因为prev指针的存在,使得找尾十分方便,不用遍历链表,直接访问哨兵位的上一个节点即可


01a6b9e2e293440480de4a7dfbecef00.png


8e52f69b214f4810abac44545cd8cb1c.png


如果是单链表,是不是还要讨论空链表的特殊情况啊?但是,在双向循环链表中,上述代码就可包含所有情况。因为哨兵位的存在,使得链表一定不为空。

d3ec97c7803d4f808e3cbf6c65eb0fa2.png


同时,因为哨兵位的存在,我们不用传二级指针了,只用对结构体进行操作。怎么样,有没有发现双向链表的巨大优势?


运行结果

ade1b171c7a64d3cabefb2f3d7c1374d.png


头插

头插时,要注意的就是要先链接后一个节点,再链接前一个节点


4bffda338a50497da15ce0a5ea5e5ff2.png


fce89c1ee387427b944353baa765543b.png


运行结果


9690e213283d4e0086dd539dbb17311f.png


判断链表是否为空

删除值得注意的是,不能删除哨兵位,要不然后续都无法对链表进行操作,所以专门写个函数来判断除了哨兵位链表是否为空,再用assert断言返回值  


如果phead和phead->next相等,则为空,返回1,即为真 ;不相等,则不为空,返回0,即为假


ebe4fb8ddb73483593b94e703321aebf.png


尾删

经历过单链表,双向链表的尾删就显得太简单了。找尾tail直接往phead的上一位,同时创建tailPrev,在释放尾部节点后,双向链接哨兵位

fac7380be9e847dbbdd412063748046c.png


427a510512a940d1863e5850669e2157.png


运行结果


a40e0505e9c84de1b5f639e5c95f0fd4.png


头删

同样,双向链表的头删也很简单。 找头first往phead的下一位,再创建second,在释放头部空间后,双向链接哨兵位


54c77b115f0442ca92e5e44bd6f3dcf2.png


de83143e9c84418185209170d54b0bc9.png


运行结果

c6762be2096842478d7590e77f06e3ba.png

相关文章
|
8天前
|
Java
java数据结构,双向链表的实现
文章介绍了双向链表的实现,包括数据结构定义、插入和删除操作的代码实现,以及双向链表的其他操作方法,并提供了完整的Java代码实现。
java数据结构,双向链表的实现
|
1月前
|
存储 Java 索引
【数据结构】链表从实现到应用,保姆级攻略
本文详细介绍了链表这一重要数据结构。链表与数组不同,其元素在内存中非连续分布,通过指针连接。Java中链表常用于需动态添加或删除元素的场景。文章首先解释了单向链表的基本概念,包括节点定义及各种操作如插入、删除等的实现方法。随后介绍了双向链表,说明了其拥有前后两个指针的特点,并展示了相关操作的代码实现。最后,对比了ArrayList与LinkedList的不同之处,包括它们底层实现、时间复杂度以及适用场景等方面。
44 10
【数据结构】链表从实现到应用,保姆级攻略
|
2月前
|
存储 C语言
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
【数据结构】c语言链表的创建插入、删除、查询、元素翻倍
|
3月前
【数据结构OJ题】环形链表
力扣题目——环形链表
33 3
【数据结构OJ题】环形链表
|
3月前
【数据结构OJ题】复制带随机指针的链表
力扣题目——复制带随机指针的链表
48 1
【数据结构OJ题】复制带随机指针的链表
|
3月前
【数据结构OJ题】环形链表II
力扣题目——环形链表II
23 1
【数据结构OJ题】环形链表II
|
3月前
【数据结构OJ题】相交链表
力扣题目——相交链表
28 1
【数据结构OJ题】相交链表
|
2月前
【数据结构】双向带头(哨兵位)循环链表 —详细讲解(赋源码)
【数据结构】双向带头(哨兵位)循环链表 —详细讲解(赋源码)
83 4
|
2月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
2月前
|
存储 测试技术
【初阶数据结构篇】双向链表的实现(赋源码)
因为头结点的存在,plist指针始终指向头结点,不会改变。