在 JavaScript 里,链表是一种常见的数据结构,由多个节点构成,每个节点包含数据和指向下一个节点的引用。下面是对链表的详细介绍,包含链表的创建、插入、删除、查找等操作。
链表节点的定义
class ListNode {
constructor(value) {
this.value = value;
this.next = null;
}
}
链表类的定义
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
// 在链表尾部添加节点
append(value) {
const newNode = new ListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
this.length++;
return this;
}
// 在链表头部添加节点
prepend(value) {
const newNode = new ListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.next = this.head;
this.head = newNode;
}
this.length++;
return this;
}
// 根据索引获取节点
getNodeByIndex(index) {
if (index < 0 || index >= this.length) return null;
let counter = 0;
let currentNode = this.head;
while (counter !== index) {
currentNode = currentNode.next;
counter++;
}
return currentNode;
}
// 在指定索引位置插入节点
insert(index, value) {
if (index === 0) return this.prepend(value);
if (index === this.length) return this.append(value);
const newNode = new ListNode(value);
const leader = this.getNodeByIndex(index - 1);
newNode.next = leader.next;
leader.next = newNode;
this.length++;
return this;
}
// 删除指定索引位置的节点
remove(index) {
if (index < 0 || index >= this.length) return null;
if (index === 0) {
const removedNode = this.head;
this.head = this.head.next;
if (this.length === 1) {
this.tail = null;
}
this.length--;
return removedNode;
}
const leader = this.getNodeByIndex(index - 1);
const removedNode = leader.next;
leader.next = removedNode.next;
if (index === this.length - 1) {
this.tail = leader;
}
this.length--;
return removedNode;
}
// 将链表转换为数组
toArray() {
const nodes = [];
let currentNode = this.head;
while (currentNode) {
nodes.push(currentNode.value);
currentNode = currentNode.next;
}
return nodes;
}
}
使用示例
// 创建一个新的链表
const linkedList = new LinkedList();
// 在链表尾部添加节点
linkedList.append(1);
linkedList.append(2);
linkedList.append(3);
// 在链表头部添加节点
linkedList.prepend(0);
// 在指定索引位置插入节点
linkedList.insert(2, 1.5);
// 删除指定索引位置的节点
linkedList.remove(3);
// 将链表转换为数组并打印
console.log(linkedList.toArray());
上述代码中,ListNode 类用来表示链表的节点,LinkedList 类则用来表示链表。LinkedList 类包含了添加节点、删除节点、插入节点等操作的方法。最后,展示如何创建链表、添加节点、插入节点、删除节点以及将链表转换为数组。
链表的使用场景
实现栈和队列
栈和队列是常见的线性数据结构,链表可用于实现它们。栈遵循后进先出(LIFO)原则,队列遵循先进先出(FIFO)原则。借助链表,能够轻松实现这些数据结构的基本操作。
管理动态数据集合
当需要处理动态变化的数据集合时,链表能发挥很好的作用。与数组不同,链表在插入和删除元素时不需要移动大量元素,其时间复杂度为 (O(1))(在已知节点位置的情况下),所以适合频繁进行插入和删除操作的场景。
实现哈希表的冲突处理
哈希表在发生哈希冲突时,可使用链表来解决。每个哈希桶存储一个链表,当多个键映射到同一个哈希桶时,这些键值对会以链表节点的形式存储在该链表中。
class HashTableNode {
constructor(key, value) {
this.key = key;
this.value = value;
this.next = null;
}
}
class HashTable {
constructor(size = 10) {
this.buckets = new Array(size);
}
hash(key) {
let hashValue = 0;
for (let i = 0; i < key.length; i++) {
hashValue += key.charCodeAt(i);
}
return hashValue % this.buckets.length;
}
set(key, value) {
const index = this.hash(key);
const newNode = new HashTableNode(key, value);
if (!this.buckets[index]) {
this.buckets[index] = newNode;
} else {
let current = this.buckets[index];
while (current.next) {
current = current.next;
}
current.next = newNode;
}
}
get(key) {
const index = this.hash(key);
let current = this.buckets[index];
while (current) {
if (current.key === key) {
return current.value;
}
current = current.next;
}
return null;
}
}
浏览器历史记录管理
在浏览器里,历史记录的管理可以借助双向链表来实现。双向链表的每个节点代表一个浏览过的页面,用户可以通过前进和后退按钮在历史记录中移动。
任务调度
在任务调度系统中,链表可用于管理待执行的任务队列。新任务可添加到链表尾部,调度器按顺序从链表头部取出任务执行。
这些场景都体现了链表在动态数据处理、频繁插入删除操作等方面的优势,能够提高程序的性能和效率。

443

被折叠的 条评论
为什么被折叠?



