2.1 栈数据结构
栈是一种**后进先出(LIFO)**原则的有序集合。
函数调用栈:A 调用 B,B 中又调用 C ,C 中又调用 D。
会先将 A 压入栈,A 没有执行完,所以不会弹出栈
在 A 执行过程中调用了 B ,会将 B 压入栈,这时候 B 在栈顶,A 在栈底
如果这时候 B 可以执行完,那么 B 会弹出栈,但是 B 没有执行完,它调用了 C
所以 C 会压入栈,并且在栈顶,而 C 调用了 D ,D 会压入栈顶
当前栈顺序:栈底 A -> B -> C -> D 栈顶
D 执行完,弹出栈,之后 C B A 依次弹出栈
题目:有 6 个元素 6,5,4,3,2,1 按顺序进栈,问下列哪一个不是合法的出栈顺序?
A:5 4 3 6 1 2 (√)
B:4 5 3 2 1 6 (√)
C:3 4 6 5 2 1 (×)
D:2 3 4 1 5 6 (√)
解析:
题目所说的按顺序进栈指的不是一次性全部进栈,而是有进有出,进栈顺序为 6 -> 5 -> 4 -> 3 -> 2 -> 1。
- A 答案:65 进栈,5 出栈,4 进栈出栈,3 进栈出栈,6 出栈,21 进栈,1 出栈,2 出栈(整体入栈顺序符合 654321)。
- B 答案:654 进栈,4 出栈,5 出栈,3 进栈出栈,2 进栈出栈,1 进栈出栈,6 出栈(整体的入栈顺序符合 654321)。
- C 答案:6543 进栈,3 出栈,4 出栈,之后应该 5 出栈而不是 6,所以错误。
- D 答案:65432 进栈,2 出栈,3 出栈,4 出栈,1 进栈出栈,5 出栈,6 出栈。符合入栈顺序。
2.2 栈结构实现
2.2.1 栈常见的一些方法
push()
添加一个新元素到栈顶位置。pop()
移除栈顶的元素,同时返回被移除的元素。peek()
返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它)。isEmpty()
如果栈里没有任何元素就返回true
,否则返回false
。size()
返回栈里的元素个数。这个方法和数组的length
属性类似。toString()
将栈结构的内容以字符串的形式返回。clear()
移除栈里的所有元素。
2.2.2 ES6 实现
class Stack {
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;
}
// 返回以字符串形式的栈内元素数据
toString() {
let result = "";
for (let item of this.items) {
result += item + " ";
}
return result;
}
// 清空栈元素
clear() {
this.items = [];
}
}
2.2.3 使用
let stack = new Stack();
// push() 测试
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.items); //--> [1, 2, 3]
// pop() 测试
console.log(stack.pop()); //--> 3
// peek() 测试
console.log(stack.peek()); //--> 2
// isEmpty() 测试
console.log(stack.isEmpty()); //--> false
// size() 测试
console.log(stack.size()); //--> 2
// toString() 测试
console.log(stack.toString()); //--> 1 2
// clear() 测试
console.log(stack.clear()); // --> undefined
2.3 简单应用
利用栈结构的特点封装实现十进制转换为二进制的方法。
function dec2bin(dec) {
// new 一个 Stack,保存余数
let rem = new Stack();
// 当不确定循环次数时,使用 while 循环
while (dec > 0) {
// 除二取余法
rem.push(dec % 2); // 获取余数,放入栈中
dec = Math.floor(dec / 2); // 除数除以二,向下取整
}
let binaryString = "";
// 不断地从栈中取出元素(0 或 1),并拼接到一起。
while (!rem.isEmpty()) {
binaryString += rem.pop();
}
return binaryString;
}
// dec2bin() 测试
console.log(dec2bin(100)); //--> 1100100
console.log(dec2bin(88)); //--> 1011000
还可以实现任意进制转换。
function baseConverter(dec, base) {
let rem = new Stack();
const digits = '0123456789ABCDEF'
let baseString = '';
while(dec > 0) {
rem.push(dec % base);
dec = Math.floor(dec / base);
}
while(!rem.isEmpty()) {
// 将十进制转为16进制时,保证结果正确
baseString += digits[rem.pop()];
}
return baseString;
}
console.log(baseConverter(100345, 2)); //--> 11000011111111001
console.log(baseConverter(100345, 8)); //--> 303771
console.log(baseConverter(100345, 16)); // --> 187F9