Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

双向链表与循环链表(进阶)

复习

  • 单向链表:节点保存数据并指向下一个节点
  • 引用与指针:保存数据的位置而非内容
  • 数组与链表:连续与链式各有取舍

本章为进阶内容,零基础读者可以跳过,不影响后续阅读。

TL;DR

  • 双向链表每个节点还保存指向前一个的指针
  • 它让“往回走”成为可能,删除也更方便
  • 循环链表首尾相接,适合循环往复的场景
  • 多存链接换来更多操作优势,也多花一点空间

正文

  单向链表只能一路向前。如果走到一半发现走过了头,想退回去,就只能从头再来。这一章看看两个常见的改进。

双向链表:能往回走

  双向链表(doubly linked list)的每个节点多存一个指针:不仅指向下一个,也指向前一个。

  多出来的这个指针,换来两个直接的好处:

  • 可以反向遍历:想往前、往后都行
  • 删除更方便:只要拿到目标节点本身,就能借助前驱指针直接把它摘掉,不必再从头找到它前面那个

  代价也是显然的:每个节点多占一个指针的空间,插入和删除时要多维护一处指针,容易出错。

循环链表:首尾相接

  循环链表(circular linked list)则把最后一个节点的指针指回第一个,首尾相连,形成一个环。

  它适合那些循环往复的场景:转了一圈又回到开头,天然对应“轮流”“轮转”的逻辑。比如:

  • 多个任务轮流执行
  • 固定大小的缓冲区循环使用

  当然,成环也意味着遍历要小心:不能简单地“走到空就停”,得设定好终止条件,否则会一圈圈转下去。

多一份链接,多一份能力

  这两个变体的思路是一致的:多保存一些链接信息,就能换来更多的操作能力。

  这和前面反复出现的主线一模一样:用空间(多存指针)换时间或便利。没有免费的增强,每多一分能力,就多一分空间开销和实现复杂度——是否值得,还是要看你主要做哪些操作。

  至此,我们有了数组、链表这两类“线性结构”。接下来,看看两种更强调“操作顺序”的抽象:栈和队列。

思考题 1

  双向链表比单向链表多保存了什么?它换来了哪些操作上的优势?

思考题 2

  循环链表适合什么样的场景?

小结

知识点

  • 双向链表节点保存前驱与后继指针
  • 双向链表支持反向遍历,删除更方便
  • 循环链表首尾相接,适合轮转场景
  • 变体都体现了“多存链接换能力”的取舍

参考资料

  1. Wikipedia(zh):双向链表:每个节点保存前后两个指针
  2. Wikipedia(zh):循环链表:首尾相接形成环的链表

思考题答案(仅供参考)

思考题 1

  多保存了指向“前一个节点”的指针。换来的优势是:可以反向遍历;删除某个已知节点时,不必再从头去找它的前驱,直接借助前驱指针就能摘掉它,操作更方便。

思考题 2

  适合需要循环往复的逻辑,比如多个任务轮流执行、固定大小缓冲区反复使用等。因为首尾相接,转一圈能自然回到起点,正对应“轮流”的语义。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪