很多面试官都喜欢让人现场手写代码,以考验一个人逻辑思维能力。因为链表代码中到处都是指针的操作、边界条件处理等,稍有不慎就容易产生Bug。所以链表代码写的好坏最可以看出一个人写代码是否足够细心,考虑问题是否全面,思维是否缜密。
极客时间课程《数据结构与算法之美》中,王争根据他的学习经历和工作经验,分享了六个写链表代码的技巧。
技巧一:理解指针或引用的含义
事实上,看懂链表的结构并不是很难,但是要把它和指针混在一起就很容易让人摸不着头脑。所以,要想写对链表代码,首先要理解好指针。
在C语言中,有指针的概念,而在JAVA、Python等语言中,取而代之的是“引用”的概念,不管是“引用”还是“指针”,本质上他们是一样的,都是用于存储所指对象的内存地址。
关于指针的概念,用一句话来辅助理解一下:
- 将某个变量赋值给指针,实际上是将这个变量的地址赋值给了这个指针
- 或者可以反过来说,被赋值的指针中,存储了这个变量的内存地址,通过指针可以找到这个变量。
技巧二:警惕指针丢失或者内存泄漏
常见的指针丢失实例:
我们希望在一个单链表的结点a和结点b之间插入结点x,一定要先用结点x指向结点b,然后再用结点a指向结点x,如果修改指向的顺序写反了,就会造成指针丢失。
内存泄漏:是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
在有些语言中,比如C语言,内存管理由程序员负责,如果没有手动释放结点对应的内存,就会造成内存泄漏。如果插入结点时指针丢失,或者删除结点时未手动释放内存空间,都会造成内存泄漏。
技巧三:利用哨兵简化实现难度
在链表的头部和尾部进行插入、删除等操作时,一般需要特殊处理,实现起来往往会比较繁琐,不简洁,而且也容易出错。引入不直接参与业务逻辑的“哨兵”结点,可以很好的解决边界问题。
哨兵结点,放置在链表的最前端,在任何时候,不管链表是否为空,head指针都会一直指向这个哨兵结点。我们把这种有哨兵结点的链表称为带头链表,相反,没有哨兵结点的链表称为不带头链表。

技巧四:重点留意边界条件处理
软件开发中,代码在一些边界或者极端情况下最容易产生BUG。要实现没有BUG的链表代码,对于边界情况一定要重点考虑。
几个常见的边界特殊情况:
- 链表为空
- 链表只含一个结点
- 链表只含两个结点
- 头结点和尾结点
技巧五:举例画图,辅助思考
链表操作中的指针跳转,是一个挺复杂的事情,单靠脑袋思考,很容易被绕晕。所以可以用举例法与画图法来辅助思考,避免脑容量不够。
技巧六:多写多练,没有捷径
以上只是总结出来的思维技巧,真正想把链表相关的问题做透,还是需要多做练习题,熟能生巧!
列举五个常见的链表操作:
- 单链表翻转
- 链表中环的检测
- 两个有序的链表合并
- 删除链表倒数第n个结点
- 求链表的中间结点