链表介绍
线性表的链式存储结构生成的表,称作“链表”。
每个元素本身由两部分组成:
- 本身的信息,称为“数据域”;
- 指向直接后继的指针,称为“指针域”
链表和数组的对比
数组的特点
- 线性结构,顺序存储
- 数组最好用于索引有寓意的情况
- 最大的优点:支持快速查询
链表的特点
- 线性结构,随机存储
- 链表不适用于索引有寓意的情况
- 最大优点:动态(真正的动态数据结构)
链表基本结构
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
实现一个链表
1. 为链表设置虚拟头结点

const dummyHead = Symbol("head");
class LinkedList {
constructor() {
// 虚拟头结点,方便遍历
this[dummyHead] = new Node(null);
this.size = 0;
}
// 打印链表信息
toString() {
let res = ''
let cur = this[dummyHead].next;
while(cur != null) {
res += cur.data + '->';
cur = cur.next;
}
res += 'NULL';
return res;
}
}
2. 在链表中添加新元素
class LinkedList {
// ...
// 在链表的index(0-based)位置添加新的元素 data
add(index, data) {
if (index < 0 || index > this.size) {
throw 'Add failed, Illegal index.'
}
let prev = this[dummyHead];
for (let i = 0; i < index; i++) {
prev = prev.next
}
const newNode = new Node(data);
newNode.next = prev.next;
prev.next = newNode;
this.size ++;
}
// 在链表头添加新的元素
addFirst(data) {
this.add(0, data)
}
// 在链表末尾添加新的元素
addLast(data) {
this.add(this.size, data)
}
// 打印链表信息
toString() {
let res = ''
let cur = this[dummyHead].next;
while(cur != null) {
res += cur.data + '->';
cur = cur.next;
}
res += 'NULL';
return res;
}
}
3. 获得链表第n个位置元素
class LinkedList {
// ...
// 获得链表的第index(0-based)个位置的元素
get(index) {
if (index < 0 || index >= this.size) {
throw 'get failed, Illegal index.'
}
let cur = this[dummyHead].next
for(let i = 0; i < index; i++) {
cur = cur.next
}
return cur.data
}
// 获得链表的第一个元素
getFirst(){
return this.get(0);
}
// 获得链表的最后一个元素
getLast() {
return this.get(this.size - 1)
}
}
4. 修改链表的第index(0-based)个位置的元素为data
class LinkedList {
// ...
set(index, data) {
if (index < 0 || index >= this.size) {
throw 'set failed, Illegal index.'
}
let cur = this[dummyHead].next;
for(let i = 0; i < index; i ++ ) {
cur = cur.next
}
cur.data = data
}
}
5. 删除链表中第n个位置的元素
class LinkedList {
// ...
// 从链表中删除index(0-based)位置的元素, 返回删除的元素
remove(index) {
if (index < 0 || index >= this.size) {
throw 'remove failed, Illegal index.'
}
let prev = this[dummyHead];
for(let i = 0; i < index; i++) {
prev = prev.next
}
let retNode = prev.next;
prev.next = retNode.next;
retNode.next = null
this.size --;
return retNode;
}
// 从链表中删除第一个元素, 返回删除的元素
removeFirst() {
return this.remove(0)
}
// 从链表中删除最后一个元素, 返回删除的元素
removeLast() {
return this.remove(this.size - 1)
}
}
6. 从链表中删除元素data
class LinkedList {
// ...
removeElement(data) {
let prev = this[dummyHead];
while(prev.next !== null) {
if(prev.next.data === data) {
break;
}
prev = prev.next;
}
if(prev.next !== null) {
let delNode = prev.next;
prev.next = delNode.next;
delNode.next = null;
this.size --;
}
}
}
7. 查找链表中是否有元素data
class LinkedList {
// ...
contains(data) {
let cur = this[dummyHead].next;
while(cur.next !== null) {
if(cur.data === data) {
return true
}
cur = cur.next
}
return false
}
}
链表时间复杂度分析
- 增:O(n)
- 删:O(n)
- 改:O(n)
- 查:O(n)