# 栈
栈是一种尊从后进先出(LIFO)原则的有序集合。新添加的或待删除的元素都保存在栈的同一端,称作栈顶,另一端叫栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底。
# 对象形式的 stack
class Stack {
constructor() {
this.count = 0;
this.items = {};
}
push(element) {
this.items[this.count] = element; // 属性名为 count
this.count++;
}
pop() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
}
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
isEmpty() {
return this.count === 0;
}
size() {
return this.count;
}
clear() {
/* while (!this.isEmpty()) {
this.pop()
} */
this.items = {};
this.count = 0;
}
toString() {
if (this.isEmpty()) {
return "";
}
let objString = `${this.items[0]}`;
for (let i = 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
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
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
# 数组形式的 stack
export default class StackArray {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
clear() {
this.items = [];
}
toArray() {
return this.items;
}
toString() {
return this.items.toString();
}
}
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
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
# 十进制转其他进制
// 十进制转二进制
function decimalToBinary(decNumber) {
let remStack = [];
let rem;
let binaryString = "";
while (decNumber > 0) {
rem = Math.floor(decNumber % 2);
remStack.push(rem);
decNumber = Math.floor(decNumber / 2);
}
while (remStack.length) {
binaryString += remStack.pop().toString();
}
return binaryString;
}
// 十进制转换为任意进制 (要转换的数字, 基数)
function baseConverter(decNumber, base) {
const remStack = [];
const digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
let number = decNumber;
let rem;
let baseString = "";
if (!(base >= 2 && base <= 36)) {
return "";
}
while (number > 0) {
rem = Math.floor(number % base);
remStack.push(rem);
number = Math.floor(number / base);
}
while (remStack.length) {
baseString += digits[remStack.pop()];
}
return baseString;
}
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
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
# 平衡圆括号
// 两种写法都是 匹配一对删除一对,第一种方法更好,不需要遍历全部的字符串
// 支持 ([{}])
function parenthesesChecker(symbols) {
const stack = [];
const opens = "([{";
const closers = ")]}";
let balanced = true;
let index = 0;
let symbol;
let top;
while (index < symbols.length && balanced) {
symbol = symbols[index]; // 依次拿出索引为 index 的字符
if (opens.indexOf(symbol) >= 0) {
// 如果是 ([{ 说明是左半边的一个符号,放入 stack
stack.push(symbol);
} else if (stack.length === 0) {
// 如果 stack 没有了左半边的符号,但是有右半边的符号,说明不匹配
balanced = false;
} else {
// 拿出 stack 数组中保存左半边的一位,和当前拿到的这位比较,看是否是对应的右半边,如果不是说明不符合,这里注意 while 循环会将连续的左半边一起放入 stack 中,如果某一位不是左半边,那么这位必定和 stack 中最后一位相匹配才行
top = stack.pop();
if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
balanced = false;
}
}
index++;
}
return balanced && !stack.length;
}
// 支持 [({})] 另一种写法
function is_balance(str) {
const [first, ...others] = str;
const stack = [first];
while (others.length > 0) {
const c = stack[stack.length - 1];
const n = others.shift();
if (!match(n, c)) {
stack.push(n);
} else {
stack.pop();
}
}
return stack.length === 0;
}
function match(n, c) {
return (
(c === "[" && n === "]") ||
(c === "{" && n === "}") ||
(c === "(" && n === ")")
);
}
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
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
# 汉诺塔
汉诺塔移动规则:
/**
* 输出汉诺塔移动规则 https://www.cnblogs.com/dmego/p/5965835.html 三根柱子是固定的,盘子一上来从小到大放到 第一根柱子上,移动次数与盘子个数的关系 2^n - 1 (n 为盘子数)
* plates 盘子个数
* source 代表第一个柱子
* helper 代表第中间个柱子
* dest 代表第三个柱子
* moves 为最后保存的移动轨迹
*/
function hanoi(plates, source, helper, dest, moves = []) {
if (plates <= 0) {
return moves;
}
if (plates === 1) {
moves.push([source, dest]); // 1 个盘子 A -> C
} else {
hanoi(plates - 1, source, dest, helper, moves); // 把 n-1 个盘子由 A -> B
moves.push([source, dest]); // 把第 n 个盘子由 A移到 C
hanoi(plates - 1, helper, source, dest, moves); // 把 n-1 个盘子由 B 移到 C
}
return moves;
}
console.log(hanoi(3, "source", "helper", "dest"));
// [["source","dest"],["source","helper"],["dest","helper"],["source","dest"],["helper","source"],["helper","dest"],["source","dest"]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
完善汉诺塔,输出各个柱子上的盘子详情:
/**
* 原理同上
*/
function towerOfHanoi(
plates,
source,
helper,
dest,
sourceName,
helperName,
destName,
moves = []
) {
if (plates <= 0) {
return moves;
}
if (plates === 1) {
dest.push(source.pop());
const move = {};
move[sourceName] = source.toString();
move[helperName] = helper.toString();
move[destName] = dest.toString();
moves.push(move);
} else {
towerOfHanoi(
plates - 1,
source,
dest,
helper,
sourceName,
destName,
helperName,
moves
);
dest.push(source.pop());
const move = {};
move[sourceName] = source.toString();
move[helperName] = helper.toString();
move[destName] = dest.toString();
moves.push(move);
towerOfHanoi(
plates - 1,
helper,
source,
dest,
helperName,
sourceName,
destName,
moves
);
}
return moves;
}
function hanoiStack(plates) {
// 初始化,声明三根柱子,并且将 plates 个盘子放到 source 柱子上
const source = [];
const dest = [];
const helper = [];
for (let i = plates; i > 0; i--) {
source.push(i);
}
return towerOfHanoi(plates, source, helper, dest, "source", "helper", "dest");
}
console.log(hanoiStack(2));
// [{"source":"2","dest":"","helper":"1"},{"source":"","helper":"1","dest":"2"},{"helper":"","source":"","dest":"2,1"}]
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
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