在计算机科学中,链表是一种基本却强大的数据结构,它通过"链接"的方式将离散的数据节点有序地组织起来。与数组相比,链表在特定场景下具有显著优势,是编程中不可或缺的工具。
链表的本质
链表本质上是一种线性数据结构,它由一系列节点组成,每个节点包含两部分关键信息:
- 数据域:存储实际元素值
- 指针域:指向下一个节点的引用
这种设计使链表成为一种离散存储结构,各节点可以分散在内存各处,通过指针连接成一个完整的序列。

链表与数组的区别
数组是连续存储的线性结构,而链表则是由指针连接的离散结构。这一根本差异导致了它们在操作效率上的显著不同:
操作 | 数组 | 链表 |
---|---|---|
访问元素 | O(1) | O(n) |
插入元素 | O(n) | O(1)* |
删除元素 | O(n) | O(1)* |
*前提是已知目标节点的前一个节点
链表的实现原理
链表的基本实现非常简洁。以JavaScript为例:
javascript
function ListNode(val, next) {
this.val = val;
this.next = next ? next : null;
}
一个简单的节点定义就能支撑起整个链表结构。创建一个包含多个元素的链表:
javascript
const head = new ListNode('a');
let node = head;
for(let i = 0; i < 10; i++) {
node.next = new ListNode(i);
node = node.next;
}
这段代码展示了链表构建的核心思想:
- 创建一个头节点作为起点
- 用一个变量指向当前操作的节点
- 通过移动这个变量来构建链表结构
链表操作的核心思想
链表操作有一个重要原则:头节点通常不能直接移动,我们需要创建辅助指针变量来遍历和操作链表。
遍历链表
javascript
let current = head;
while (current) {
console.log(current.val); // 处理节点
current = current.next; // 移动到下一节点
}
插入节点
在节点A之后插入节点X:
javascript
X.next = A.next; // X指向A的下一节点
A.next = X; // A指向X
删除节点
删除A之后的节点:
javascript
A.next = A.next.next; // A直接指向被删节点的下一节点
链表的实际应用
让我们看一个实际的算法问题:合并两个有序链表:
javascript
function mergeTwoLists(list1, list2) {
let head = new ListNode(); // 创建哑节点
let current = head;
// 比较两个链表的节点值,选择较小的添加到结果链表
while (list1 && list2) {
if (list1.val < list2.val) {
current.next = list1;
list1 = list1.next;
} else {
current.next = list2;
list2 = list2.next;
}
current = current.next;
}
// 处理剩余节点
current.next = list1 || list2;
return head.next; // 返回哑节点的下一个节点
}
这个例子展示了链表操作的典型模式:
- 创建哑头节点简化边界情况
- 使用游标指针操作链表
- 通过改变指针指向而非数据移动来重组链表
链表的变体
除了基本的单向链表,还有其他几种常见变体:
- 双向链表:每个节点有两个指针,分别指向前一个和后一个节点
- 循环链表:尾节点指向头节点,形成一个环
总结
链表作为一种基础数据结构,其核心优势在于高效的插入删除操作。虽然它在随机访问上不如数组,但在需要频繁增删元素且较少随机访问的场景中,链表往往是更优的选择。