第二章、队列和双端队列
队列
队列遵循先进先出原则。
class Queue {
constructor() {
// 已添加过的总数量,包括已移除的
this.count = 0;
// 当前队列最前端的项
this.lowestCount = 0;
this.items = {};
}
// 添加元素
enqueue(item) {
this.items[this.count] = item;
this.count++;
}
// 移除元素
dequeue() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
}
// 查看队列头部元素
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.lowestCount];
}
// 队列大小
size() {
// 队列总大小减去当前第一项的索引即为队列的当前大小
return this.count - this.lowestCount;
}
// 检查是否为空
isEmpty() {
return this.size() === 0;
}
// 清空队列
clear() {
this.count = 0;
this.lowestCount = 0;
this.items = {};
}
// 返回队列内容
toString() {
if (this.isEmpty()) {
return "";
}
let objString = `${this.items[this.lowestCount]}`;
for (let i = this.lowestCount + 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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
双端队列
双端队列允许从队列的前端或者后端移除元素。
class Deque {
constructor() {
// 已添加过的总数量,包括已移除的
this.count = 0;
// 当前队列最前端的项
this.lowestCount = 0;
this.items = {};
}
// 前端添加元素
addFront(item) {
if (this.isEmpty()) {
// 当前队列为空情况
this.addBack(item);
} else if (this.lowestCount > 0) {
// 当前队列有被移除过元素的情况,即第一个元素下标不是0
this.lowestCount--;
this.items[this.lowestCount] = item;
} else {
// 当前队列第一个下标为0的情况
// 队列整体后移
for (let i = this.count; i > 0; i--) {
this.items[i] = this.items[i - 1];
}
this.count++;
this.lowestCount = 0;
this.items[0] = item;
}
}
// 后端添加元素
addBack(item) {
this.items[this.count] = item;
this.count++;
}
// 前端移除元素
removeFront() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
}
// 后端移除元素
removeBack() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
}
// 查看队列头部元素
peekFront() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.lowestCount];
}
// 查看队列尾部元素
peekBack() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
// 队列大小
size() {
// 队列总大小减去当前第一项的索引即为队列的当前大小
return this.count - this.lowestCount;
}
// 检查是否为空
isEmpty() {
return this.size() === 0;
}
// 清空队列
clear() {
this.count = 0;
this.lowestCount = 0;
this.items = {};
}
// 返回队列内容
toString() {
if (this.isEmpty()) {
return "";
}
let objString = `${this.items[this.lowestCount]}`;
for (let i = this.lowestCount + 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
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
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
使用队列和双端队列解决问题
循环队列--击鼓传花游戏
这是一个队列的修改版本,循环队列,实现是将读取完的元素放到队列的末尾,形成队列的循环读取。
function loopQueue(itemList, num) {
const queue = new Queue();
const outItemList = []
// 将给定的参数全部储存进队列
for(let i =0;i<itemList.length;i++){
queue.enqueue(itemList[i])
}
// 当队列中元素多余两个的时候进行循环,即进行传花游戏
while(queue.size() > 1){
for(let i=0;i<num; i++){
// 循环指定的次数,每次都将队列最前端的项放到队列末尾
queue.enqueue(queue.dequeue())
}
// 指定传递次数结束之后,将队列第一个元素抛出,即淘汰手上有花的人
outItemList.push(queue.dequeue())
}
return {
// 每次经过给定次数循环后被淘汰的元素组成的数组
outItem: outItemList,
// 队列中最后会只剩一个元素,即传花游戏的冠军
winner: queue.dequeue()
}
}
const names = ["a","b","c","d","e","f","g","h","i"]
const result = loopQueue(names, 8)
console.log(result)
// {
// outItem: (8) ["i", "a", "c", "f", "d", "e", "b", "g"]
// winner: "h"
// }
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
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
回文检查器
使用双端队列检查某一个字符串是否为回文
function palindromeCheck(str) {
// 只检测字符串
if (Object.prototype.toString.call(str) !== "[object String]") {
return false;
}
const deque = new Deque();
// 将字符串转为数组,并且不区分大小写,统一转为小写
const strList = str.toLocaleLowerCase().split("");
let isEqual = true;
let firstChar, lastChar;
for (let i = 0; i < strList.length; i++) {
deque.addBack(strList[i]);
}
while (deque.size() > 1 && isEqual) {
firstChar = deque.removeFront();
lastChar = deque.removeBack();
// 如果某个字符串是回文,那么转为双端队列之后,当前队列取出来的第一项跟最后一项应该相同
if (firstChar !== lastChar) {
isEqual = false;
}
}
return isEqual
}
console.log(palindromeCheck("asD dsa")) // true
// 案例只是展示双端队列思想,JS中可以直接判断字符串是不是回文
function palindromeCheck(str) {
return str.toLocaleLowerCase() === str.toLocaleLowerCase().split("").reverse().join("")
}
console.log(palindromeCheck("asD dsa")) // true
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
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