怎么用js封装一个单向链表
首先,我应该定义节点类,每个节点有value和next属性。接下来是链表类,需要有头节点指针,可能还需要记录长度。然后考虑方法,比如append在末尾添加,prepend在头部添加,insert在指定位置插入,remove删除节点,还有查找和反转等方法。
插入和删除需要考虑边界情况,比如头部和尾部的处理。比如,删除头节点时,需要将头节点指向下一个节点。插入到指定位置时,要找到前一个节点,调整指针。
反转链表是一个常见的操作,可以用迭代或递归的方法。这里可能用迭代更直观,维护前一个、当前和下一个节点,逐个反转指针。
然后,考虑测试这些方法。比如创建链表实例,添加节点,插入,删除,反转,然后输出结果是否正确。
需要注意的是,JS中没有指针,所以用对象的引用来模拟指针。另外,要处理索引越界的情况,比如插入或删除时位置是否有效。
可能用户对链表的概念不是很熟悉,所以步骤要详细,代码示例要清晰,并解释每个方法的作用和实现逻辑。还要说明每个方法的时间复杂度,比如插入删除在头部是O(1),其他位置需要遍历是O(n)。
最后,总结单向链表的优缺点,比如插入删除比数组高效,但查找需要遍历。可能用户实际应用场景是什么?比如需要频繁插入删除,不需要随机访问的情况。好的,我将分步骤详细讲解如何用JavaScript实现单向链表,并提供可运行的代码示例:
一、节点类封装
class Node {
constructor(value) {
this.value = value; // 节点存储的值
this.next = null; // 指向下一个节点的指针(默认为null)
}
}
二、链表类基本框架
class LinkedList {
constructor() {
this.head = null; // 链表头指针
this.length = 0; // 链表长度计数器
}
}
三、核心方法实现
- 尾部追加节点 $$时间复杂度: O(n)$$ ```javascript append(value) { const newNode = new Node(value);
if (!this.head) { // 空链表情况处理 this.head = newNode; } else { let current = this.head; while (current.next) { // 遍历到最后一个节点 current = current.next; } current.next = newNode; }
this.length++; }
2. 头部插入节点
$$时间复杂度: O(1)$$
```javascript
prepend(value) {
const newNode = new Node(value);
newNode.next = this.head; // 新节点指向原头节点
this.head = newNode; // 更新头指针
this.length++;
}
- 指定位置插入 $$时间复杂度: O(n)$$ ```javascript insert(index, value) { if (index < 0 || index > this.length) return false;
if (index === 0) { this.prepend(value); return true; }
const newNode = new Node(value); let prev = this.head;
// 找到插入位置的前驱节点 for (let i = 0; i < index - 1; i++) { prev = prev.next; }
newNode.next = prev.next; prev.next = newNode; this.length++; return true; }
4. 删除指定位置节点
$$时间复杂度: O(n)$$
```javascript
removeAt(index) {
if (index < 0 || index >= this.length) return null;
let removedNode;
if (index === 0) {
removedNode = this.head;
this.head = this.head.next;
} else {
let prev = this.head;
for (let i = 0; i < index - 1; i++) {
prev = prev.next;
}
removedNode = prev.next;
prev.next = prev.next.next;
}
this.length--;
return removedNode.value;
}
- 链表反转(经典算法) $$时间复杂度: O(n)$$ ```javascript reverse() { let prev = null; let current = this.head;
while (current) { const nextTemp = current.next; // 临时保存下一个节点 current.next = prev; // 反转指针方向 prev = current; // 前移prev指针 current = nextTemp; // 前移current指针 }
this.head = prev; // 更新头指针 }
四、辅助方法
1. 转换为数组(方便调试)
```javascript
toArray() {
const result = [];
let current = this.head;
while (current) {
result.push(current.value);
current = current.next;
}
return result;
}
- 查找元素 ```javascript contains(value) { let current = this.head;
while (current) { if (current.value === value) return true; current = current.next; }
return false; }
五、使用示例
```javascript
const list = new LinkedList();
list.append(10);
list.prepend(5);
list.insert(1, 7);
console.log(list.toArray()); // [5, 7, 10]
list.reverse();
console.log(list.toArray()); // [10, 7, 5]
list.removeAt(1);
console.log(list.toArray()); // [10, 5]
六、应用场景说明
- 需要频繁在头部插入/删除操作
- 内存空间不连续的特殊需求
- 实现撤销操作(通过链表记录操作历史)
- 实现队列/栈等数据结构的基础
注意事项:
- 注意处理空链表边界条件
- 操作前先验证索引有效性
- 插入/删除后及时更新length属性
- 使用临时变量保存断开前的指针引用
通过这个实现,您可以掌握链表的核心操作逻辑,后续可根据需求扩展更多方法(如清空链表、获取中间节点等)。
相关推荐
















