如何快速掌握链表?

103 阅读2分钟

理解指针的含义

指针中存储了数据的内存地址,在javascript中,我们可以把指针简单的理解为引用,类似对象的引用。

警惕指针丢失和内存泄漏

在写链表代码时,指来指去很容易就不知道指到哪了,所以在写的时候一定注意不要丢失指针。
具体的例子,在链表中插入结点x

截屏2022-01-02 下午8.38.56.png 如果这样实现代码,就会发生指针丢失和内存泄漏

p.next = x; // p指向x
x.next = p.next; x再指向p

乍一看好像没问题,第一行代码p指向了x,第二行p.x就相当于x,实际上是x指向了自己,这时候链表的被分为了两部分,后半部分就丢失了。 对于某些语言,内存管理是由程序员来负责的,这时候就会出现内存泄露。那么怎么来改一下呢

x.next = p.next;
p.next = x;

这样调换一下顺序问题就解决了,所以我们在操作结点的时候,一定要注意操作的顺序。

合理利用头结点

只需要上面两行代码就可以实现链表的插入操作,但是这只能满足大多数的操作场景,如果是往空链表中插入一个元素这两行代码就行不通了,需要进行一下判断单独处理

if(!head){
    head = x;
}

删除结点也会遇到同样的问题 上面的情况很容易因为考虑不全而出错,那么怎么解决呢?我们只需要增加一个头结点,这个结点一般不存储数据,只是存储链表第一个结点的地址。这样不管链表是不是为空,这个结点都是存在的,我们把这种带头结点的链表叫做带头链表,相反,不带头结点的链表叫做不带头链表。
因为头结点始终都存在,所以插入和删除操作就可以统一为相同的逻辑了

留意边界条件的处理

常见的边界条件如下:

  • 链表为空代码是否正常工作
  • 当只有1个或者两个结点是否正常工作
  • 处理头结点、第一个结点和尾结点是否正常工作

通过画图来辅助思考

对于稍微复杂的链表操作,比如前面我们提到的单链表反转,指针一会儿指这,一会儿指那,一会儿就被绕晕了。总感觉脑容量不够,想不清楚。所以这个时候就要使用大招了,举例法和画图法。

没有捷径,多练

推荐题目如下

  • 单链表反转
  • 链表中环的检测
  • 合并两个有序列表
  • 删除链表倒数第n个结点
  • 求链表的中间结点

具体题目解法见下面笔记: