栈是一种遵从后进先出(LIFO)原则的有序集合。
新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端叫做栈底。
在栈里,新元素靠近栈顶,旧元素接近栈底。
在现实生活中也有很多栈的例子,比如餐厅里堆放的盘子,最先放的盘子在最底下,最后放的盘子在最上面。
一、栈的创建
function Stack () {
//创建一个数组,保存栈里的元素
var items = [];
/*声明一些方法*/
/*
push(element(s))
添加一个或几个新元素到栈顶
*/
this.push = function(element){
items.push(element);
};
/*
pop()
移除栈顶的元素,同时返回被移除的元素
*/
this.pop = function(){
return items.pop();
};
/*
peek()
返回栈顶的元素,不对栈做任何修改
不会移除栈顶的元素,仅仅返回它
*/
this.peek = function(){
return items[items.length-1];
};
/*
isEmpty()
如果栈里没有任何元素就返回true,否则返回false
*/
this.isEmpty = function(){
return items.length == 0;
};
/*
size()
返回栈里的元素个数
和数组的length属性类似
*/
this.size = function(){
return items.length;
};
/*
clear()
移除栈里的所有元素
*/
this.clear = function(){
items = [];
};
/*
print()
辅助方法,将栈里的元素输出到控制台
*/
this.print = function(){
console.log(items.toString());
};
}
二、使用Stack类
//初始化Stack类
var stack = new Stack();
//验证栈是否为空
console.log(stack.isEmpty()); //输出为true
//向栈里添加元素
stack.push(5);
stack.push(6);
console.log(stack.peek()); //输出6
stack.push(11);
console.log(stack.size()); //输出3
console.log(stack.isEmpty()); //输出为false
//从栈里移除两个元素
stack.pop();
stack.pop();
console.log(stack.size()); //输出1
stack.print(); //输出5
三、应用实例
1、进制转换
1)从十进制到二进制
function divideBy2 (decNumber) {
var remStack = new Stack(),
rem,
binaryString = '';
while (decNumber > 0) {
rem = Math.floor(decNumber % 2);
remStack.push(rem);
decNumber = Math.floor(decNumber / 2);
}
while (!remStack.isEmpty()) {
binaryString += remStack.pop().toString();
}
return binaryString;
}
2)从十进制到任意进制
function baseConverter (decNumber, base) {
var remStack = new Stack(),
rem,
baseString = '',
digits = '0123456789ABCDEF';
while (decNumber > 0) {
rem = Math.floor(decNumber % base);
remStack.push(rem);
decNumber = Math.floor(decNumber / base);
}
while (!remStack.isEmpty()) {
baseString += digits[remStack.pop()];
}
return baseString;
}
2、平衡圆括号
function parenthesesChecker (symbols) {
let stack = new Stack(),
balanced = true,
index = 0,
symbol, top,
opens = "([{",
closers = ")]}";
while (index < symbols.length && balanced){
symbol = symbols.charAt(index);
if (opens.indexOf(symbol) >= 0){
stack.push(symbol);
console.log(`open symbol - stacking ${symbol}`);
} else {
console.log(`close symbol ${symbol}`);
if (stack.isEmpty()){
balanced = false;
console.log('Stack is empty, no more symbols to pop and compare');
} else {
top = stack.pop();
if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
balanced = false;
console.log(`poping symbol ${top} - is not a match compared to ${symbol}`);
} else {
console.log(`poping symbol ${top} - is is a match compared to ${symbol}`);
}
}
}
index++;
}
if (balanced && stack.isEmpty()){
return true;
}
return false;
}
3、汉诺塔
function towerOfHanoi(n, from, to, helper){
if (n > 0){
towerOfHanoi(n-1, from, helper, to);
to.push(from.pop());
console.log('-----');
console.log('Disk: ' + n);
console.log('Source: ');
from.print();
console.log('Destination: ');
to.print();
console.log('Helper: ');
helper.print();
towerOfHanoi(n-1, helper, to, from);
}
}
var source = new Stack();
source.push(3);
source.push(2);
source.push(1);
var dest = new Stack();
var helper = new Stack();
towerOfHanoi(source.size(), source, dest, helper);
【注】关于print()方法需要注意一点,该方法中已经包含了console.log()方法,直接使用就可以在控制台上打印输出。
【补充】
function towerOfHanoi(n, from, to, helper){
if (n > 0){
towerOfHanoi(n-1, from, helper, to);
console.log('移动盘子 ' + n + ' 从 ' + from + ' 到 ' + to);
towerOfHanoi(n-1, helper, to, from);
}
}
towerOfHanoi(3, 'A', 'B', 'C');