1. 什么是 LinkedList
LinkedList是一种常见的数据结构,它由一系列节点组成,每个节点包含一个值和指向下一个节点的指针。相比于数组,它具有更灵活的插入和删除操作,但是访问单个节点的时间复杂度较高。
在Javascript中,可以使用对象的引用来实现LinkedList。例如,下面是一个简单的LinkedList的实现:
class Node {
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 Node(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
this.length++;
}
// 在链表指定位置插入一个节点
insert(position, value) {
if (position < 0 || position > this.length) {
return false;
}
const newNode = new Node(value);
if (position === 0) {
newNode.next = this.head;
this.head = newNode;
if (!this.tail) {
this.tail = newNode;
}
} else if (position === this.length) {
this.tail.next = newNode;
this.tail = newNode;
} else {
let currentNode = this.head;
let previousNode = null;
let index = 0;
while (index < position) {
previousNode = currentNode;
currentNode = currentNode.next;
index++;
}
previousNode.next = newNode;
newNode.next = currentNode;
}
this.length++;
return true;
}
// 根据位置删除一个节点
removeAt(position) {
if (position < 0 || position >= this.length) {
return false;
}
let currentNode = this.head;
let previousNode = null;
let index = 0;
if (position === 0) {
this.head = currentNode.next;
if (this.length === 1) {
this.tail = null;
}
} else if (position === this.length - 1) {
while (currentNode.next) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = null;
this.tail = previousNode;
} else {
while (index < position) {
previousNode = currentNode;
currentNode = currentNode.next;
index++;
}
previousNode.next = currentNode.next;
}
this.length--;
return currentNode.value;
}
// 查找一个节点的位置
indexOf(value) {
let currentNode = this.head;
let index = 0;
while (currentNode) {
if (currentNode.value === value) {
return index;
}
currentNode = currentNode.next;
index++;
}
return -1;
}
// 根据值删除一个节点
remove(value) {
const index = this.indexOf(value);
return this.removeAt(index);
}
// 将链表转换为字符串
toString() {
let currentNode = this.head;
let string = '';
while (currentNode) {
string += currentNode.value;
if (currentNode.next) {
string += ' -> ';
}
currentNode = currentNode.next;
}
return string;
}
// 判断链表是否为空
isEmpty() {
return this.length === 0;
}
// 返回链表的长度
size() {
return this.length;
}
}
const list = new LinkedList();
list.append(1);
list.append(2);
list.append(3);
list.insert(1, 'a');
list.remove(2);
console.log(list.toString()); // 1 -> a -> 3
2. LinkedList 的优点
2.1 灵活的插入和删除操作
LinkedList具有非常灵活的插入和删除操作,因为只需要改变节点之间的指针即可。相比之下,数组的插入和删除操作则需要移动大量的元素,因此时间复杂度较高。
2.2 动态内存分配
LinkedList可以动态地分配内存,因为每个节点只需要在它被添加到链表中时创建,而在它被删除后则可以立刻释放内存。相比之下,数组却需要预先分配一定大小的内存空间。
3. LinkedList 的缺点
3.1 访问元素需要遍历
因为LinkedList的节点不必在内存中连续存放,因此访问单个节点的时间复杂度为O(n)。相比之下,数组可以在O(1)的时间内访问单个元素。
3.2 空间开销大
相比于数组,LinkedList需要额外的指针来指向下一个节点,因此需要更多的内存空间。
4. 使用 LinkedList 的场景
4.1 需要频繁地插入和删除元素
如果需要频繁地向一个集合中插入和删除元素,LinkedList可以极大地简化代码实现。
4.2 需要处理大型数据集合
如果需要处理的数据集合非常大,LinkedList可以动态分配内存,避免浪费过多的内存空间。
5. 小结
LinkedList是一种常见的数据结构,具有灵活的插入和删除操作以及动态内存分配的优点。不过,它的访问时间复杂度较高,同时也需要更多的内存空间。