JavaScript 中的链表实现

2025 年 4 月 7 日 | 阅读 4 分钟

链表是最基本的数据结构之一。在接下来的部分,我们将探讨链表的类型,然后用 JavaScript 实现链表。在本文的最后,你将了解链表,并能自信地在代码中使用链表。

什么是链表?

链表是一种线性结构,其中数据元素存储在不连续的位置,并且元素通过 指针 连接(指针是存储内存地址的变量)。节点由两部分组成:

  1. 数据:节点包含的数据。
  2. 指针:指向序列中的下一个节点(如果是最后一个节点,则为 null)。

与数组不同,链表不分配连续内存。相反,每个节点都指向下一个节点,形成一个链式结构。这是因为链表可以在不移动内存中任何内容的情况下增加或减小大小,使其更加动态。

链表类型

它有多种变体,每种都适用于不同的用例。让我们讨论三种主要的链表类型及其描述和代码片段。

单向链表

在单向链表中,每个节点都指向下一个节点。每个列表节点包含两部分数据和一个指向下一个节点的链接。最后一个节点的指针指向 null,表示列表的末尾。

特性

  • 单向(只能沿一个方向遍历)。
  • 实现简单。

JavaScript 实现

代码

示例

编译并运行

输出

 
10
20
30   

双向链表

双向链表是单向链表的增强版本,增加了额外的指针。每个节点包含三个组件:

  1. 数据
  2. 指向下一个节点的指针
  3. 指向前一个节点的指针

特性

  • 双向遍历(可以向前和向后遍历)。
  • 更灵活,但需要额外的内存来存储额外的指针。

JavaScript 实现

代码

示例

编译并运行

输出

 
10
20
30
30
20
10  

循环链表

对于循环链表,最后一个节点的引用不是 null,而是指向第一个节点,从而形成一个循环链。循环链表,与其他链表一样,可以是单向的(单向连接)或双向的(双向连接)。

特性

  • 该列表没有 null 引用。
  • 适用于需要循环流动的用例(例如轮循调度)。

JavaScript 实现(单向循环)

代码

示例

编译并运行

输出

 
10
20
30

链表与数组之间的主要区别

特性链表Array
内存分配动态连续的
插入/删除高效(头部或尾部 O(1))昂贵(O(n) 由于需要移动)
访问时间顺序(O(n))随机(O(1))
灵活性可以动态增长/缩小某些语言中大小固定

链表的优点

  1. 动态大小:与固定大小的数组不同,链表具有动态大小。
  2. 高效的插入/删除:对于在链表头部/尾部插入或删除,只需要 O(1) 的时间复杂度,因为我们只需要更改一些指针即可完成添加和移除操作。
  3. 内存利用:由于链表不需要连续的内存块,因此可用于动态内存分配。
  4. 队列/栈实现的简便性:链表可用于实现其他数据结构,如队列和栈。

链表的缺点

  1. 顺序访问:链表中的元素通过从头节点开始访问,其复杂度为 (O(n)),而数组中的元素是随机访问的,其复杂度为 (O(1))。
  2. 内存开销:每个节点都包含一个额外的指针/引用,与数组相比,内存占用更多。
  3. 复杂操作:与数组相比,访问、搜索或遍历链表更慢、更复杂。
  4. 缓存性能:链表中的元素随机散布在内存中,导致缓存性能不佳。

结论

链表是一种非常灵活和动态的数据结构,是许多高级算法和系统的基本构建块。尽管与 数组 相比,链表需要更多的内存用于指针并且访问速度较慢,但其动态性使其在频繁添加和删除元素的场景中具有独特的强大功能。因此,学习单向、双向和循环链表可以帮助以非常高效和健壮的方式开发 JavaScript 应用程序。