javascript数据结构与算法(二)

链表

链表相比数组最重要的优点, 那就是无须移动链表中的元素,就能轻松地添加和移除元素。因此,当你需要添加和移除很多元 素时,最好的选择就是链表,而非数组。

创建链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
function defaultEquals(a, b) {
return a === b;
}

class Node {
constructor(element) {
this.element = element;
this.next = undefined;
}
}

class LinkedList {
constructor(equalsFn = defaultEquals) {
this.count = 0;
this.head = undefined;
this.equalsFn = equalsFn; // 可以传入深比较函数
}

// 向链表尾部添加元素
push(element) {
const node = new Node(element);
let current;

if (this.head == null) {
this.head = node;
} else {
current = this.head;
while (current.next != null) {
//获得最后一项
current = current.next;
}
// 将其 next 赋为新元素,建立链接
current.next = node;
}
this.count++;
}

// 从链表的特定位置移除一个元素
removeAt(index) {
// 检查越界值
if (index >= 0 && index < this.count) {
let current = this.head;
// 移除第一项
if (index === 0) {
this.head = current.next;
} else {
// let previous;
// for (let i = 0; i < index; i++) {
// previous = current;
// current = current.next;
// }
// // 将previous与current的下一项链接起来:跳过current,从而移除它
// previous.next = current.next;

// 使用getElementAt重构
let previous = this.getElementAt(index - 1);
current = previous.next;
previous.next = current.next;
}
this.count--;
return current.element;
}
return undefined;
}

// 循环迭代链表直到目标位置
getElementAt(index) {
if (index >= 0 && index < this.count) {
let current = this.head;
for (let i = 0; i < index && current != null; i++) {
current = current.next;
}
return current.element;
}
return undefined;
}

// 在任意位置插入元素
insert(element, index) {
if (index >= 0 && index < this.count) {
const node = new Node(element);
if (index === 0) {
// 在第一个位置添加
const current = this.head;
node.next = current;
this.head = node;
} else {
const previous = this.getElementAt(index - 1);
const current = previous.next;
node.next = current;
previous.next = node;
}
this.count++;
return true;
}
return undefined;
}

// 返回一个元素的位置
indexOf(element) {
let current = this.head;
for (let i = 0; i < this.count && current != null; i++) {
if (this.equalsFn(current.element, element)) {
return i;
}
current = current.next;
}
return -1;
}

// 从链表中移除一个元素
remove(element) {
const index = this.indexOf(element);
return this.removeAt(index);
}

size() {
return this.count;
}

isEmpty() {
return this.size() === 0;
}

getHead() {
return this.head;
}

toString() {
if (this.head == null) {
return "";
}
let objString = "";
let current = this.head.next;
for (let i = 1; i < this.size() && current != null; i++) {
objString = `${objString},${current.element}`;
current = current.next;
}
return objString;
}
}

双向链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class DoublyNode extends Node {
constructor(element, next, prev) {
super(element, next);
this.prev = prev;
}
}

class DoublyLinkedList extends LinkedList {
constructor(equalsFn = defaultEquals) {
super(equalsFn);
this.tail = undefined; // 链表最后一个元素的引用
}

// 在任意位置插入新元素
insert(element, index) {
if (index >= 0 && index <= this.count) {
const node = new DoublyNode(element);
let current = this.head;
if (index === 0) {
if (this.head == null) {
this.head = node;
this.tail = node;
} else {
node.next = this.head;
current.prev = node;
this.head = node;
}
} else if (index === this.count) {
current = this.tail;
current.next = node;
node.prev = current;
this.tail = node;
} else {
const previous = this.getElementAt(index - 1);
current = previos.next;
node.next = current;
previous.next = node;
current.prev = node;
node.prev = previous;
}
this.count++;
return true;
}
return false;
}

// 从任意位置移除元素
removeAt(index) {
if (index >= 0 && index < this.count) {
let current = this.head;
if (index === 0) {
this.head = current.next;
if (this.count === 1) {
// 如果只有一项,更新tail
this.tail = undefined;
} else {
this.head.prev = undefined;
}
} else if (index === this.count - 1) {
current = this.tail;
this.tail = current.prev;
this.tail.next = undefined;
} else {
current = this.getElementAt(index);
const previous = current.prev;
previous.next = current.next;
current.next.prev = previous;
}
this.count--;
return current.element;
}
return undefined;
}

getTail() {
return this.tail;
}

clear() {
super.clear();
this.tail = undefined;
}
}

循环链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class circleLinkedList extends LinkedList {
constructor(equalsFn = defaultEquals) {
super(equalsFn);
}

// 在任意位置插入元素
insert(element, index) {
if (index >= 0 && index < this.count) {
const node = new Node(element);
const current = this.head;
if (index === 0) {
if (thi.head == null) {
this.head = node;
node.next = this.head;
} else {
node.next = current;
current = this.getElementAt(this.size() - 1);
// 更新最后一个元素
this.head = node;
current.next = this.head;
}
} else {
const previous = this.getElementAt(index - 1);
const current = previous.next;
node.next = current;
previous.next = node;
}
this.count++;
return true;
}
return undefined;
}

// 从链表的特定位置移除一个元素
removeAt(index) {
// 检查越界值
if (index >= 0 && index < this.count) {
let current = this.head;
// 移除第一项
if (index === 0) {
if (this.size() === 0) {
this.head = undefined;
} else {
const removed = this.head;
current = this.getElementAt(this.size() - 1);
this.head = this.head.next;
current.next = this.head;
current = removed; // 更新 current 变量的引用,这样就能返回它(行{6})来表示移除元素的值。
}
} else {
// 使用getElementAt重构
let previous = this.getElementAt(index - 1);
current = previous.next;
previous.next = current.next;
}
this.count--;
return current.element; // 行{6}
}
return undefined;
}
}

有序链表

有序链表 是指保持元素有序的链表结构。除了使用排序算法之外,我们还可以将元素插入到
正确的位置来保证链表的有序性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const Compare = { LESS_THAN: -1, BIGGER_THAN: 1 };

function defaultCompare(a, b) {
if (a === b) {
return 0;
}
return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
}
class SortedLinkedList extends LinkedList {
constructor(equalsFn = defaultEquals, compareFn = defaultCompare) {
super(equalsFn);
this.compareFn = compareFn;
}

insert(element, index = 0) {
if (this.isEmpty()) {
return super.insert(element, 0);
}
const pos = this.getIndexNextSortedElement(element);
return super.insert(element, pos);
}

getIndexNextSortedElement(element) {
let current = this.head;
let i = 0;
for (; i < this.size() && current; i++) {
const comp = this.compareFn(element, current.element);
if (comp === Compare.LESS_THAN) {
return i;
}
current = current.next;
}
return i;
}
}

创建 StackLinkedlist 类

用链表模拟栈数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class StackLinkedList {
constructor() {
this.items = new DoublyLinkedList();
}

push(element) {
this.items.push(element);
}

pop() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items.removeAt(this.size() - 1);
return result;
}

peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items.getElementAt(this.size() - 1).element;
}

isEmpty() {
return this.items.isEmpty();
}

size() {
return this.items.size();
}

clear() {
this.items.clear();
}

toString() {
return this.items.toString();
}
}
liborn wechat
欢迎您扫一扫上面的微信二维码,订阅我的公众号!