下面从多个方面进行介绍,并给出对应的 JavaScript 示例。
存储结构
- 顺序表(数组) :
顺序表使用一段连续的内存空间来存储元素。就像一排连着的房子,每个房子(内存单元)依次存放数据元素,通过元素的下标可以直接计算出其在内存中的地址,从而快速访问元素。 - 单链表:
单链表的节点在内存中是离散存储的,每个节点除了存储数据,还包含一个指向下一个节点的指针。节点之间通过指针相连,就像用绳子串起来的珠子,每个珠子(节点)可以放在不同的地方,通过绳子(指针)依次连接。
访问元素的效率
- 顺序表(数组) :
可以通过下标直接访问元素,时间复杂度为 。这是因为数组在内存中是连续存储的,根据下标和数组首地址可以快速计算出元素的存储位置。 - 单链表:
访问元素需要从头节点开始,沿着指针依次遍历,直到找到目标节点。因此,访问第 个元素的时间复杂度为 ,平均时间复杂度为 ,其中 是链表的长度。
插入和删除元素的效率
- 顺序表(数组) :
在数组中间插入或删除元素时,需要移动后续的元素,时间复杂度为 。因为要为新元素腾出位置或填补删除元素后的空位,需要将大量元素依次向后或向前移动。 - 单链表:
如果已知要插入或删除位置的前一个节点,插入和删除操作只需要修改指针,时间复杂度为 。但如果不知道前一个节点,需要从头节点开始遍历找到该位置,平均时间复杂度为 。
空间复杂度
-
顺序表(数组) :
需要预先分配连续的内存空间,可能会造成内存的浪费或不足。如果数组的长度固定,当元素数量超过数组容量时,需要重新分配更大的数组并复制元素。 -
单链表:
可以动态分配内存,每个节点只在需要时分配空间,不会造成大量的内存浪费。但每个节点需要额外的指针域来存储指向下一个节点的指针,会增加一定的空间开销。
JavaScript 示例代码
// 顺序表(数组)示例 // 创建一个顺序表(数组) const array = [1, 2, 3, 4, 5];
// 访问元素 console.log("顺序表访问元素:", array[2]); // 时间复杂度 O(1)
// 插入元素 array.splice(2, 0, 6); // 时间复杂度 O(n) console.log("顺序表插入元素后:", array);
// 删除元素 array.splice(2, 1); // 时间复杂度 O(n) console.log("顺序表删除元素后:", array);
// 单链表示例 // 定义链表节点类 class Node { constructor(data) { this.data = data; this.next = null; } }
// 定义链表类 class LinkedList { constructor() { this.head = null; }
// 向链表尾部添加节点
append(data) {
const newNode = new Node(data);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
}
// 访问第 index 个元素
get(index) {
let current = this.head;
let count = 0;
while (current && count < index) {
current = current.next;
count++;
}
return current? current.data : null; // 时间复杂度 O(n)
}
// 在第 index 个位置插入元素
insert(index, data) {
const newNode = new Node(data);
if (index === 0) {
newNode.next = this.head;
this.head = newNode;
} else {
let current = this.head;
let count = 0;
while (current && count < index - 1) {
current = current.next;
count++;
}
if (current) {
newNode.next = current.next;
current.next = newNode;
}
}
}
// 删除第 index 个元素
remove(index) {
if (!this.head) return;
if (index === 0) {
this.head = this.head.next;
} else {
let current = this.head;
let count = 0;
while (current && count < index - 1) {
current = current.next;
count++;
}
if (current && current.next) {
current.next = current.next.next;
}
}
}
}
//创建一个单链表 const linkedList = new LinkedList(); linkedList.append(1); linkedList.append(2); linkedList.append(3);
// 访问元素 console.log("单链表访问元素:", linkedList.get(2)); // 时间复杂度 O(n)
// 插入元素 linkedList.insert(2, 4); // 时间复杂度 O(n) console.log("单链表插入元素后,第 2 个元素为:", linkedList.get(2));
// 删除元素 linkedList.remove(2); // 时间复杂度 O(n) console.log("单链表删除元素后,第 2 个元素为:", linkedList.get(2));
代码解释
-
顺序表(数组)部分:
- 使用 JavaScript 的数组来模拟顺序表。通过
[]直接创建数组,使用下标[]访问元素,splice方法插入和删除元素。
- 使用 JavaScript 的数组来模拟顺序表。通过
-
单链表部分:
- 定义了
Node类表示链表节点,包含数据域data和指向下一个节点的指针next。 - 定义了
LinkedList类表示链表,包含头节点head。实现了append方法向链表尾部添加节点,get方法访问指定位置的元素,insert方法在指定位置插入元素,remove方法删除指定位置的元素。
- 定义了