链表作为经典的数据结构,在JavaScript中有着广泛的应用场景。本文将深入探讨链表的实现原理、核心操作以及在实际开发中的最佳实践。
链表的基本概念和原理
链表(Linked List)是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的引用。与数组不同,链表在内存中不需要连续的空间存储。
链表的核心特性
- 动态内存分配:节点可以在运行时动态创建和销毁
- 非连续存储:节点可以分散在内存的不同位置
- 插入删除高效:在已知位置的情况下,插入和删除操作时间复杂度为O(1)
- 随机访问较慢:访问特定位置的元素需要从头遍历,时间复杂度为O(n)
常见链表类型
graph LR
A[链表类型] --> B[单向链表]
A --> C[双向链表]
A --> D[循环链表]
B --> E[每个节点指向下一个]
C --> F[节点有前后两个指针]
D --> G[尾节点指向头节点]
JavaScript中链表的实现方法
单向链表实现
// 链表节点类
class ListNode {
constructor(data) {
this.data = data; // 节点数据
this.next = null; // 指向下一个节点的引用
}
}
// 单向链表类
class SinglyLinkedList {
constructor() {
this.head = null; // 链表头节点
this.size = 0; // 链表长度
}
// 在链表末尾添加节点
append(data) {
const newNode = new ListNode(data);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
this.size++;
return this;
}
// 在指定位置插入节点
insert(index, data) {
if (index < 0 || index > this.size) {
throw new Error('Index out of bounds');
}
const newNode = new ListNode(data);
if (index === 0) {
newNode.next = this.head;
this.head = newNode;
} else {
let current = this.head;
for (let i = 0; i < index - 1; i++) {
current = current.next;
}
newNode.next = current.next;
current.next = newNode;
}
this.size++;
return this;
}
// 删除指定位置的节点
removeAt(index) {
if (index < 0 || index >= this.size) {
throw new Error('Index out of bounds');
}
let removedNode;
if (index === 0) {
removedNode = this.head;
this.head = this.head.next;
} else {
let current = this.head;
for (let i = 0; i < index - 1; i++) {
current = current.next;
}
removedNode = current.next;
current.next = current.next.next;
}
this.size--;
return removedNode.data;
}
// 查找节点
find(data) {
let current = this.head;
let index = 0;
while (current) {
if (current.data === data) {
return { node: current, index };
}
current = current.next;
index++;
}
return null;
}
// 反转链表
reverse() {
let prev = null;
let current = this.head;
let next = null;
while (current) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
this.head = prev;
return this;
}
// 获取链表长度
getSize() {
return this.size;
}
// 检查链表是否为空
isEmpty() {
return this.size === 0;
}
// 将链表转换为数组
toArray() {
const result = [];
let current = this.head;
while (current) {
result.push(current.data);
current = current.next;
}
return result;
}
// 清空链表
clear() {
this.head = null;
this.size = 0;
}
}