1.定义
栈是一种遵从后进先出(LIFO)原则的有序集合。从栈顶添加或删除元素。现实生活中的栈有:一摞书或者叠放的盘子等。
2.实现Stack——基于数组
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 = [];
}
toString() {
return this.items.toString();
}
}
3.实现Stack——基于对象
class Stack {
constructor() {
this.count = 0;
this.items = {};
}
push(element) {
this.items[this.count] = element;
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() {
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;
}
}
4.栈的应用
(1)十进制转二进制
function decimalToBinary(decNumber) {
const remStack = new Stack();
let number = decNumber;
let rem;
let binaryString = '';
while (number > 0) {
rem = Math.floor(number % 2);
remStack.push(rem);
number = Math.floor(number / 2);
}
while (! remStack.isEmpty()) {
binaryString += remStack.pop().toString();
}
return binaryString;
}
console.log(decimalToBinary(233)); //11101001
console.log(decimalToBinary(10)); //1010
console.log(decimalToBinary(1000)); //1111101000
(2)平衡圆括号
function parenthesesChecker(symbols) {
const stack = new Stack();
const opens = '([{';
const closers = ')]}';
let balanced = true;
let index = 0;
let symbol;
let top;
while (index < symbols.length && balanced) {
symbol = symbols[index];
if (opens.indexOf(symbol) >= 0) {
stack.push(symbol);
} else if (stack.isEmpty()) {
balanced = false;
} else {
top = stack.pop();
if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
balanced = false;
}
}
index++;
}
return balanced && stack.isEmpty();
}
console.log(parenthesesChecker('{([])}')); //true
console.log(parenthesesChecker('{{([][])}()}')); //true
console.log(parenthesesChecker('[{()]')); //false
(3)汉诺塔
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) {
const source = new Stack();
const dest = new Stack();
const helper = new Stack();
for (let i = plates; i > 0; i--) {
source.push(i);
}
return towerOfHanoi(plates, source, helper, dest, 'source', 'helper', 'dest');
}
function hanoi(plates, source, helper, dest, moves = []) {
if (plates <= 0) {
return moves;
}
if (plates === 1) {
moves.push([source, dest]);
} else {
hanoi(plates - 1, source, dest, helper, moves);
moves.push([source, dest]);
hanoi(plates - 1, helper, source, dest, moves);
}
return moves;
}
console.log(hanoiStack(3));
console.log(hanoi(3, 'source', 'helper', 'dest'));
5.总结
使用数组创建Stack会更简单一点,有数组方法可以使用。在使用数组时,大部分方法的时复杂度是O(n),在最坏的情况下需要迭代整个数组才能找到要找的那个元素。为了保证元素排列有序,数组会占用更多的内存空间。
使用对象存储所有的栈元素,我们能够直接获取元素,占用较少的内存空间,仍然保证元素的顺序和LIFO原则。