Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b421a34

Browse files
committed
增加栈结构的封装及测试
1 parent c3457e0 commit b421a34

File tree

7 files changed

+260
-7
lines changed

7 files changed

+260
-7
lines changed

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- [JavaScript 数据结构与算法(一)前言](./assets/doc/JavaScript数据结构与算法(一)前言.md)
66
- [JavaScript 数据结构与算法(二)数组结构](./assets/doc/JavaScript数据结构与算法(二)数组结构.md)
7+
- [JavaScript 数据结构与算法(三)栈结构](./assets/doc/JavaScript数据结构与算法(三)栈结构.md)
78

89
## 代码测试环境
910

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
title: JavaScript 数据结构与算法(三)栈结构
3+
date: 2020年07月21日 11:49:12
4+
tags: [JavaScript, 数据结构, 算法, 栈]
5+
categories: [算法专辑]
6+
---
7+
8+
数组是一个线性结构,并且可以在数组的任意位置插入和删除元素。
9+
但是有时候,我们为了实现某些功能,必须对这种任意性加以限制。
10+
栈和队列就是比较常见的受限的线性结构。
11+
12+
栈(stack)是一种运算受限的线性表:
13+
14+
- `LIFO(last in first out)`表示就是后进入的元素,第一个弹出栈空间。类似于自动餐托盘,最后放上的托盘,往往先把拿出去使用。
15+
- 其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
16+
- 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;
17+
- 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
18+
19+
如下图所示:
20+
![stack](https://user-images.githubusercontent.com/24516169/88035463-caf63780-cb74-11ea-910d-e396a83659ea.png)
21+
22+
栈的特点:**先进后出,后进先出**
23+
24+
### 程序中的栈结构
25+
26+
- 函数调用栈:A(B(C(D()))):
27+
即 A 函数中调用 B,B 调用 C,C 调用 D;在 A 执行的过程中会将 A 压入栈,随后 B 执行时 B 也被压入栈,函数 C 和 D 执行时也会被压入栈。所以当前栈的顺序为:A->B->C->D(栈顶);函数 D 执行完之后,会弹出栈被释放,弹出栈的顺序为 D->C->B->A;
28+
29+
- 递归:
30+
为什么没有停止条件的递归会造成栈溢出?比如函数 A 为递归函数,不断地调用自己(因为函数还没有执行完,不会把函数弹出栈),不停地把相同的函数 A 压入栈,最后造成栈溢出(Stack Overfloat)。
31+
32+
### 练习
33+
34+
题目:有 6 个元素 6,5,4,3,2,1 按顺序进栈,问下列哪一个不是合法的出栈顺序?
35+
36+
- A:5 4 3 6 1 2 (√)
37+
- B:4 5 3 2 1 6 (√)
38+
- C:3 4 6 5 2 1 (×ばつ)
39+
- D:2 3 4 1 5 6 (√)
40+
41+
题目所说的按顺序进栈指的不是一次性全部进栈,而是有进有出,进栈顺序为 6 -> 5 -> 4 -> 3 -> 2 -> 1。
42+
43+
解析:
44+
45+
- A 答案:65 进栈,5 出栈,4 进栈出栈,3 进栈出栈,6 出栈,21 进栈,1 出栈,2 出栈(整体入栈顺序符合 654321)。
46+
- B 答案:654 进栈,4 出栈,5 出栈,3 进栈出栈,2 进栈出栈,1 进栈出栈,6 出栈(整体的入栈顺序符合 654321)。
47+
- C 答案:6543 进栈,3 出栈,4 出栈,之后应该 5 出栈而不是 6,所以错误。
48+
- D 答案:65432 进栈,2 出栈,3 出栈,4 出栈,1 进栈出栈,5 出栈,6 出栈。符合入栈顺序。
49+
50+
### 栈结构实现
51+
52+
#### 栈常见的操作
53+
54+
- `push()`:添加一个新元素到栈顶位置。
55+
- `pop()`:移除栈顶的元素,同时返回被移除的元素。
56+
- `peek()`:返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它)。
57+
- `isEmpty()`:如果栈里没有任何元素就返回 `true`,否则返回 `false`
58+
- `size()`:返回栈里的元素个数。这个方法和数组的 `length` 属性类似。
59+
- `toString()`:将栈结构的内容以字符串的形式返回。
60+
61+
#### JavaScript 代码实现栈结构
62+
63+
```js
64+
// 使用 ES6 实现
65+
class Stack {
66+
items = [];
67+
68+
// push() 压栈操作,给栈中添加元素
69+
push(item) {
70+
this.items.push(item);
71+
}
72+
73+
// pop() 出栈操作,从栈中取出元素,并返回取出的那个元素
74+
pop() {
75+
return this.items.pop();
76+
}
77+
78+
// peek() 查看栈顶元素
79+
peek() {
80+
return this.items[this.items.length - 1];
81+
}
82+
83+
// isEmpty() 判断栈是否为空
84+
isEmpty() {
85+
return this.items.length === 0;
86+
}
87+
88+
// size() 获取栈中元素个数
89+
size() {
90+
return this.items.length;
91+
}
92+
93+
// toString() 返回以字符串形式的栈内元素数据
94+
toString() {
95+
let result = "";
96+
for (let item of this.items) {
97+
result += item + " ";
98+
}
99+
return result;
100+
}
101+
}
102+
```
103+
104+
#### 测试栈结构
105+
106+
```js
107+
const stack = new Stack();
108+
stack.push(1);
109+
stack.push(22);
110+
stack.push(333);
111+
stack.push(4444);
112+
console.log(stack.items); //--> [1, 22, 333, 4444]
113+
114+
console.log(stack.pop()); //--> 444
115+
console.log(stack.pop()); //--> 333
116+
console.log(stack.peek()); //--> 22
117+
console.log(stack.isEmpty()); //--> false
118+
console.log(stack.size()); //--> 2
119+
console.log(stack.toString()); //--> 1 22
120+
```
121+
122+
### 栈结构的简单应用
123+
124+
利用栈结构的特点封装十进制转换为二进制的函数。
125+
126+
### 代码实现
127+
128+
```js
129+
// 十进制转换成二进制
130+
function dec2bin(dec) {
131+
// new 一个 Stack,保存余数
132+
const stack = new Stack();
133+
134+
// 当不确定循环次数时,使用 while 循环
135+
while (dec > 0) {
136+
// 除二取余法
137+
stack.push(dec % 2); // 获取余数,放入栈中
138+
dec = Math.floor(dec / 2);
139+
}
140+
141+
let binaryString = "";
142+
// 不断地从栈中取出元素(0 或 1),并拼接到一起。
143+
while (!stack.isEmpty()) {
144+
binaryString += stack.pop();
145+
}
146+
147+
return binaryString;
148+
}
149+
```
150+
151+
#### 测试
152+
153+
```js
154+
// 验证十进制转换二进制方法
155+
console.log(dec2bin(10)); //--> 1010
156+
console.log(dec2bin(100)); //--> 1100100
157+
```

‎assets/doc/JavaScript数据结构与算法(二)数组结构.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
- 添加一个元素到数组的最后位置 `array.push(item)`
2020
- 在数组首位插入一个元素 `array.unshift(item)`
21-
- 在指定索引位置插入元素 `array.splice(index, 0, item)`
21+
- 在指定索引位置插入元素 `array.splice(index.js, 0, item)`
2222
splice() 第二个参数为 0 时,表示插入数据。
2323
```js
2424
let myArray = [1, 2, 3];
@@ -42,14 +42,14 @@
4242

4343
### 修改元素
4444

45-
- 修改指定索引位置的元素 `array.splice(index, 1, item)`
45+
- 修改指定索引位置的元素 `array.splice(index.js, 1, item)`
4646
```js
4747
let myArray3 = [1, 2, 3, 4, 5, 6];
4848
// 修改 索引 1 的位置的元素为 AA
4949
myArray2.splice(1, 1, "AA");
5050
console.log(myArray3); //--> [1, "AA", 3, 4, 5, 6]
5151
```
52-
- 修改指定索引位置的几个元素 `array.splice(index, number, item)`
52+
- 修改指定索引位置的几个元素 `array.splice(index.js, number, item)`
5353
```js
5454
let myArray4 = [1, 2, 3, 4, 5, 6, 7];
5555
// 在 索引 2 的位置起,修改两个元素为 AA BB

‎src/index.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// 在这里编写你的 ES6 代码
2-
(() => {
3-
console.log('学习 JavaScript 数据结构与算法');
4-
})();
1+
// 导入栈结构的封装及测试代码
2+
import './stack'
3+

‎src/stack/dec2bin.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Stack from './stack.js';
2+
3+
// 十进制转换成二进制
4+
export default function dec2bin(dec) {
5+
// new 一个 Stack,保存余数
6+
const stack = new Stack();
7+
8+
// 当不确定循环次数时,使用 while 循环
9+
while (dec > 0) {
10+
// 除二取余法
11+
stack.push(dec % 2); // 获取余数,放入栈中
12+
dec = Math.floor(dec / 2);
13+
}
14+
15+
let binaryString = '';
16+
// 不断地从栈中取出元素(0 或 1),并拼接到一起。
17+
while (!stack.isEmpty()) {
18+
binaryString += stack.pop();
19+
}
20+
21+
return binaryString;
22+
}

‎src/stack/index.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Stack from './stack';
2+
import dec2bin from './dec2bin';
3+
4+
// ----- 栈结构测试 -----//
5+
const stack = new Stack();
6+
7+
// push() 方法测试
8+
stack.push(1);
9+
stack.push(2);
10+
stack.push(3);
11+
console.log(stack);
12+
13+
// pop() 方法测试
14+
console.log(stack.pop());
15+
console.log(stack.pop());
16+
17+
// peek() 方法测试
18+
console.log(stack.peek());
19+
20+
// isEmpty() 方法测试
21+
console.log(stack.isEmpty());
22+
23+
// size() 方法测试
24+
console.log(stack.size());
25+
26+
// toString() 方法测试
27+
console.log(stack.toString());
28+
29+
// 利用栈结构的特点实现十进制转换为二进制的方法测试
30+
console.log(dec2bin(100));
31+
console.log(dec2bin(88));
32+
33+

‎src/stack/stack.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// 栈结构的封装
2+
export default class Stack {
3+
4+
constructor() {
5+
this.items = [];
6+
}
7+
8+
// push() 压栈操作,给栈中添加元素
9+
push(item) {
10+
this.items.push(item);
11+
}
12+
13+
// pop() 出栈操作,从栈中取出元素,并返回取出的那个元素
14+
pop() {
15+
return this.items.pop();
16+
}
17+
18+
// peek() 查看栈顶元素
19+
peek() {
20+
return this.items[this.items.length - 1];
21+
}
22+
23+
// isEmpty() 判断栈是否为空
24+
isEmpty() {
25+
return this.items.length === 0;
26+
}
27+
28+
// size() 获取栈中元素个数
29+
size() {
30+
return this.items.length;
31+
}
32+
33+
// toString() 返回以字符串形式的栈内元素数据
34+
toString() {
35+
let result = '';
36+
for (let item of this.items) {
37+
result += item + ' ';
38+
}
39+
return result;
40+
}
41+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /