栈(Stack)是限定仅在表尾进行插入和删除操作的线性表
栈是一种遵从后进先出(Last In First Out,LINFO)原则的有序集合。
新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端就叫栈底。 在栈中,新元素都靠近栈顶,旧元素都接近栈底。
现实生活中栈的例子,如:一摞书,或者厨房里堆放的盘子。
栈也被用在编程语言的编译器和内存中保存变量、方法调用等。
栈的创建
创建一个类(也就是前面将的构造函数).从最基础的开始,先声明这个类:
function Stack(){
//各种属性和方法
}
首先,需要一种数据结构来保存栈中的元素,可以选择数组:
var items =[];
接下来,为栈声明一下方法。
- push(elements(s)):添加一个(或几个)新元素到栈顶。
- pop():移除栈顶的元素,同时返回被移除的元素。
- peek():返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶元素,仅仅返回它)。
- isEmpty():如果栈里没有任何元素就返回true,否则返回false。
- clear():移除栈里的所有元素。
- size():返回栈里的元素个数。这个方法和数组的length属性很类似。
push()方法的实现。这个方法负责往栈里添加新元素,注意,该方法只添加元素到栈顶,也就是栈的末尾。
this.push = function(element){
items.push(element);
};
pop()方法的实现,这个方法主要用来移除栈里的元素。栈遵从LIFO原则,因此移出的是最后添加进去的元素。因此栈的pop()方法:
this.pop = function(){
return items.pop();
};
只能用push()和pop()方法添加和删除栈中的元素,这样,栈就遵从了LIFO原则。
peek()返回栈顶的元素:
this.peek = function(){
return items[items.length -1];
};
因为栈Stack内部是用数组保存元素的,所以访问数组最后一个元素是length-1;
isEmpty():判断栈是否为空,若栈为空。返回true,否则,返回false
this.isEmpty = function(){
return items.length ==0;
};
使用isEmpty()方法,判断数组的长度是否为0。
size():返回栈的长度,类似于数组的length属性。
this.size = function(){
return items.length;
};
clear():把栈清空。
this.clear = function(){
items = [];
};
这样栈就实现了。
为了检查栈中的内容,添加个辅助方法print()。把栈中的元素都输出到控制台。
print
this.print = function(){
console.log(items.toString());
}
这样就创建好了栈。栈的完整代码为:
function Stack(){
var items =[];
this.push = function(element){
items.push(element);
};
this.pop = function(){
return items.pop();
};
this.peek = function(){
return items[items.length -1];
};
this.isEmpty = function(){
return items.length ==0;
};
this.size = function(){
return items.length;
};
this.clear = function(){
items = [];
};
this.print = function(){
console.log(items.toString());
}
}
使用Stack类
初始化Stack类,然后验证一下栈是否为空(输出的是true,因为还没有往栈中添加元素)
var stack = new Stack();
console.log(stack.isEmpty());
往栈中添加一些元素,
stack.push(2);
stack.push(6);
stack.push(10);
使用peek()方法,将会输出10,因为它是栈中添加的最后一个元素。
console.log(stack.peek());//10
stack调用size()和isEmpty()方法
console.log(stack.size());//3
console.log(stack.isEmpty());//false
stack.push(15);
用图描述栈的操作,以及栈的当前状态。
然后,再用两次pop()方法从栈中移除2个元素。
stack.pop();
stack.pop();
console.log(stack.size()); //2
stack.print(); //2,6
代码的执行过程:
从十进制到二进制
已经学会了如何使用Stack类,现在就用它解决一些问题。
要把十进制转化成二级制(0和1)。方法:将该十进制数字和2整除(二进制满二进一),直到结果为0为止。举个例子,把十进制数字10转化成二进制数字,过程:
算法描述:
function divideBy2(number){
var remStack = new Stack(),
remainder,//余数
binaryString = '';
while(number > 0 ){
// 要转换的数字对2进行求余
remainder = Math.floor(number % 2);
// 将余数放到栈中
remStack.push(remainder);
// 对要转换的数字整除2 向下取整
number = Math.floor(number/2);
}
while(!remStack.isEmpty()){
// 用pop方法把栈中的元素都移除,把出栈的元素转化成可连接的字符串
binaryString += remStack.pop().toString();
}
return binaryString;
}
// 验证一下
console.log(divideBy2(10)); //1010
修改算法,使之能把十进制转换成任何进制(二进制、八进制、十六进制)。
function baseConverter(decNumber,base){
var remStack = new Stack(),
remainder,
baseString ='',
digits = '0123456789ABCDEF';
while(decNumber > 0){
remainder = Math.floor(decNumber % base);
remStack.push(remainder);
decNumber = Math.floor(decNumber / base);
}
while(!remStack.isEmpty()){
/*
十进制转成二进制,余数是0或1;
十进制转成八进制,余数是0-7
十进制转成16进制时,余数是0-9,再A(10)-F(15),因此需要对栈中的数字做个转化
* */
baseString += digits[remStack.pop()];
}
return baseString;
}
console.log(baseConverter(15,16)); //F
console.log(baseConverter(10,8));//12