链表:单链表与双链表的区别,初学者一看就会

想象一下,你正在开发一个简单的游戏,需要存储玩家的角色列表,比如从1号玩家到100号玩家。如果用数组来存,删除中间某个玩家时,后面的所有玩家都要往前挪位置,很麻烦。这时候,链表就派上用场了——每个玩家的信息(数据)旁边只需要记住下一个玩家是谁(指针),不需要连续的内存空间,插入删除只需要改几个指针,就像调整糖葫芦的竹签一样方便。

什么是链表?

链表是一种线性数据结构,每个元素(称为“节点”)由两部分组成:数据域(存具体信息)和指针域(存下一个/前一个节点的地址)。和数组不同,链表的节点在内存中不是连续的,就像散落的珠子用线串起来,线就是指针。

单链表:只能“单向”走的糖葫芦串

单链表是最简单的链表,每个节点只有一个指针,指向下一个节点。我们可以把它想象成一串糖葫芦,每颗山楂(节点)只知道下一颗山楂在哪里,不知道上一颗。

单链表的节点结构:

数据 | 指针 → 下一个节点

比如,存储“玩家1→玩家2→玩家3”的单链表:

玩家1数据 | → 玩家2
玩家2数据 | → 玩家3
玩家3数据 | → null(表示结束)

单链表怎么用?

  • 遍历:只能从第一个节点(头节点)开始,顺着指针一直走到最后一个节点(next为null)。比如查第5个玩家,必须从头开始数到第5个。
  • 插入/删除:要在中间插入一个节点,得先找到“目标节点的前一个节点”,然后修改指针。比如在玩家2和玩家3之间插入玩家4:
    1. 先找到玩家2(原链表:玩家1→玩家2→玩家3)
    2. 新建玩家4节点,让玩家4的指针指向玩家3
    3. 把玩家2的指针从指向玩家3,改为指向玩家4
    这样就完成了插入,不需要移动其他节点。

但如果要删除玩家3,必须先找到玩家2(前驱节点),把玩家2的指针直接指向玩家3的下一个节点(null)。

双链表:能“前后”走的糖葫芦串

双链表比单链表多了一个指针,每个节点不仅知道下一个节点是谁,还知道前一个节点是谁。现在每颗山楂不仅能被下一颗牵着,还能被上一颗牵着,像带了双向挂钩的糖葫芦。

双链表的节点结构:

前指针 ← 数据 → 后指针

比如,同样存储“玩家1→玩家2→玩家3”的双链表:

null ← 玩家1数据 → 玩家2
玩家1 ← 玩家2数据 → 玩家3
玩家2 ← 玩家3数据 → null

双链表怎么用?

  • 遍历:可以从任意节点开始,既能向前走(通过prev指针),也能向后走(通过next指针)。比如从玩家2开始,能直接找到玩家1(用prev)或玩家3(用next)。
  • 插入/删除:在已知节点处插入或删除时,双链表更方便。比如在玩家2和玩家3之间插入玩家4:
    1. 新建玩家4节点,把玩家4的prev指向玩家2
    2. 把玩家4的next指向玩家3
    3. 把玩家2的next从指向玩家3,改为指向玩家4
    4. 把玩家3的prev从指向玩家2,改为指向玩家4
    这样一步到位,不需要再找“前驱”,因为玩家2的prev已经是玩家1,玩家4可以直接和前后节点建立联系。

单链表 vs 双链表:核心区别大总结

对比项 单链表 双链表
节点结构 只有一个指针(next) 两个指针(prev + next)
遍历方向 只能单向遍历(从头到尾) 双向遍历(可前可后)
插入/删除 需要先找到“前驱节点”,修改指针 直接通过prev/next指针操作,更简单
内存占用 少一个指针,节省内存 多一个指针,内存占用稍高
适用场景 简单单向数据存储(如队列) 需要双向操作(如浏览器历史、双向链表队列)

为什么要学双链表?

如果你的游戏只需要“从头到尾”显示玩家列表,单链表足够。但如果要实现“同时显示历史记录和未来记录”(比如浏览器的前进后退),或者在链表中间频繁插入删除节点,双链表更灵活。比如在手机通讯录中,想在已知联系人处同时向前和向后添加联系人,双链表能快速完成。

总结

  • 单链表:像一串糖葫芦,只能从左到右吃,简单省空间,适合单向操作。
  • 双链表:像一串带双向挂钩的糖葫芦,能从左到右也能从右到左吃,功能更全但稍占内存,适合需要双向移动的场景。

初学者不用急着记复杂的操作,先记住“指针数量”和“遍历方向”的区别,以后遇到实际问题(比如实现一个双向链表队列)再慢慢熟悉细节~

小夜