一、单向链表
- 链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同
1. 数组
- 要存储多个元素,数组可能是最常用的数据结构
- 数组的缺点
- 数组的创建通常需要申请一段连续的内存空间(一整块的内存),并且大小是固定的,所以当当前数组不能满足容量需求时,需要扩容
- 而且在数组的开头或中间位置插入数据的成本很高,需要进行大量元素的转移
2. 链表

- 要存储多个数据,另外一个选择就是链表
- 但不同于数组,链表中的元素在内存中不必是连续的空间
- 链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用组成
- 链表的优点
- 内存空间不是必须连续的,可以充分利用计算机的内存,实现灵活的内存动态管理
- 链表不必在创建时就确定大小,并且大小可以无限的延伸下去
- 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多
- 链表的缺点
- 链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)
- 无法通过下标直接访问元素,需要从头一个个访问,直到找到对应的元素
二、封装单向链表类
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
append(value) {
const newNode = new Node(value);
if (this.head === null) {
this.head = newNode;
} else {
let current = this.head;
while (current.next !== null) {
current = current.next;
}
current.next = newNode;
}
this.size++;
}
insert(index, value) {
if (index >= 0 && index <= this.size) {
const newNode = new Node(value);
if (index === 0) {
newNode.next = this.head;
this.head = newNode;
} else {
let current = this.head;
let previous = null;
let count = 0;
while (count < index) {
previous = current;
current = current.next;
count++;
}
newNode.next = current;
previous.next = newNode;
}
this.size++;
return true;
}
return false;
}
remove(index) {
if (index >= 0 && index < this.size) {
let current = this.head;
if (index === 0) {
this.head = current.next;
} else {
let previous = null;
let count = 0;
while (count < index) {
previous = current;
current = current.next;
count++;
}
previous.next = current.next;
}
this.size--;
return current.value;
}
return null;
}
get(index) {
if (index >= 0 && index < this.size) {
let current = this.head;
let count = 0;
while (count < index) {
current = current.next;
count++;
}
return current.value;
}
return null;
}
size() {
return this.size;
}
isEmpty() {
return this.size === 0;
}
}