0 什么是栈
栈又名堆栈,是一中数据结构,只允许在一端进行数据的添加或者删除,这一端被称为栈顶,相对地,把另一端称为栈底。因而按照后进先出(LIFO, Last In First Out)的原理运作
- 示意图

特点
- 后进先出
- 最新的元素越靠近栈顶,越旧的越靠近栈底
1 es5实现栈
1.1 定义
//栈类
function Stack () {
//1 声明数组,保存栈里的元素,栈底:数组的开头位置; 栈顶:数组的末尾位置
let items = []
//2 声明栈的方法
//添加元素到栈顶,添加元素到数组的末尾
this.push = function ( ele ) {
items.push ( ele )
}
//移出栈顶元素,移出数组最后一个元素
this.pop = function () {
items.pop ()
}
//返回栈顶元素
this.peek = function () {
return items[ items.length - 1 ]
}
//检测栈中是否有元素,没有返回true,有返回false
this.isEmpty = function () {
return items.length == 0
}
//清空栈中的所有元素
this.clear = function () {
items.length = 0
}
//返回栈中元素个数
this.size = function () {
return items.length
}
//打印栈里的元素到控制台
this.print = function () {
console.log ( items.toString () )
}
}
1.2 使用
//2 使用栈
let stack1 = new Stack();//创建栈对象
console.log ( stack1.isEmpty () );//true,因为没有添加元素进去
stack1.push(3);//往栈中添加元素
stack1.push(5);//
console.log ( stack1.peek() );//取出栈顶元素,打印5
stack1.push(11);
console.log ( stack1.size () );//3
console.log ( stack1.isEmpty () );//false
stack1.push(15);
stack1.pop();
stack1.pop();
console.log ( stack1.size () );//size=2 ,因为15,11已经被移出栈了
stack1.print();
2 es6实现栈
2.1 定义
//用ECMAScript6语法实现的栈类
let Stack2 = (function () {
const items = new WeakMap();
class Stack2 {
constructor (){
items.set(this,[]);
}
push(ele){
let s = items.get(this);
s.push(ele);
}
pop(){
let s = items.get(this);
return s.pop();
}
peek(){
let s = items.get(this);
return s[s.length-1];
}
isEmpty(){
let s = items.get(this);
return s.length==0;
}
clear(){
let s = items.get(this);
s = [];
}
size(){
let s = items.get(this);
return s.length;
}
print (){
let s = items.get(this);
console.log ( s.toString () );
}
}
return Stack2;
}());
2.2 使用
let stack2 = new Stack2();//创建栈对象
console.log ( stack2.isEmpty () );//true,因为没有添加元素进去
stack2.push(3);//往栈中添加元素
stack2.push(5);//
stack2.print();
console.log ( stack2.peek() );//取出栈顶元素,打印5
stack2.push(11);
console.log ( stack2.size () );//3
console.log ( stack2.isEmpty () );//false
stack2.push(15);
stack2.print();
stack2.pop();
stack2.pop();
console.log ( stack2.size () );//size=2 ,因为15,11已经被移出栈了
stack2.print();
3 应用 使用栈进行进制转换
3.1 十进制转换为二进制数
比如十进制的12转换为二进制的12 12/2=6 余数=0 6/2=3 余数=0 3/2=1 余数=1 1/2=0 余数=1
对应的二进制为余数的倒置,即是1100
思路:
- 将十进制数对2求余数,将余数压入栈中
- 再计算十进制数除以2的结果
- 判断结果是否大于0,如果大于,重复步骤1和步骤2
- 取出栈中数据,拼接为一个字符串
function dec2Binary ( decNumber ) {
let stack1 = new Stack();
let rem;//10对2求的余数
let binaryStr = "";//存储二进制字符串
//十进制数除以2,获取余数,存储到栈中,知道该数小于等于0,结束
while(decNumber>0){
rem = Math.floor(decNumber%2);
stack1.push(rem);
decNumber = Math.floor(decNumber/2);
}
//取出栈里的数,拼接为二进制字符串
while(!stack1.isEmpty()){
binaryStr+=stack1.pop()+"";
}
return Number(binaryStr);
}
console.log ( dec2Binary ( 12 ) );
3.2 十进制转换成任意进制
十进制=>二进制 余数有0,1 十进制=>八进制 余数有0,1,2,3,.....7 十进制=>十六进制 余数有0,....9,A,B,C,D,E,F
/**
* @param decNumber 十进制数
* @param base 进制
* @return {string} 转换为base进制的数的字符串
*/
function dec2AnyNum ( decNumber,base ) {
let stack1 = new Stack();
let rem=undefined;
let tempStr = "";//存储转换后的对应进制字符串
let number = "0123456789ABCDEF";//16进制内的余数
//十进制转换为base进制,存储到stac1中
while(decNumber>0){
rem = Math.floor(decNumber%base);
stack1.push(rem);
decNumber = Math.floor(decNumber/base);
}
//base进制数,拼接为字符串
while ( !stack1.isEmpty() ) {
tempStr+= number[stack1.pop()];
}
return tempStr;
}
验证:
console.log ( dec2AnyNum ( 12, 16 ) );
3.3 二进制转换为十进制
1100(2) 二级制的12,转换为十进制的过程(公式) 1100,从栈顶取出就是0-0-1-1(2) = 12^3 + 12^2 + 02^1+02^0=8+4+0+0=12
思路:
- 将二进制数据转为为单个字符串,存储到数组中
- 将数组中的值全部压入栈中
- 循环取出栈顶的数据,对该数据进行进制转换计算(
数据*2^次方)
注意:根据栈的特性,从栈顶取出数据的顺序和原始数据顺序相反, 如1100,从栈顶取出就是0-0-1-1
function bin2Dec ( binNumber ) {
let stack1 = new Stack();
let rem = undefined;
let tempNum = 0;
var binNumberArr = (new String(binNumber)).split("");
binNumberArr.forEach(function ( ele ) {
stack1.push(ele);
});
var bin = 0;//幂数
while(!stack1.isEmpty()){
tempNum+= stack1.pop()*Math.pow(2,bin);//Math.pow(2,bin) 2的bin次方
bin++;
}
return tempNum;
}
验证:
console.log ( bin2Dec ( 1100 ) );
3.4 任意进制转换为十进制
- 准备一个0-16的映射表对象
- 数字变为单个字符串,存储到数组中
- 数组的元素压入栈
- 取出栈顶元素,通过通过映射表[元素]取得对应的数,再进行计算
/**
* @param anyNumber currentBase进制的整数
* @param currentBase 进制
* @return {number} 返回计算以后的十进制数
*/
function anyNum2Dec ( anyNumber,currentBase ) {
let stack1 = new Stack();
let tempNum = 0;
//16进制数和十进制映射表
let number = {
"0":0,
"1":1,
"2":2,
"3":3,
"4":4,
"5":5,
"6":6,
"7":7,
"8":8,
"9":9,
"A":10,
"B":11,
"C":12,
"D":13,
"E":14,
"F":15
};
//数字转换字符串,并储存为数组的元素
var anyNumberArr = (anyNumber+"").split("");
anyNumberArr.forEach(function ( ele ) {
stack1.push(ele.toUpperCase());
});
var bin = 0;//幂数
while(!stack1.isEmpty()){
tempNum+= number[stack1.pop()]*Math.pow(currentBase,bin);//Math.pow(2,bin) 2的bin次方
bin++;
}
return tempNum;
}
验证:
console.log ( anyNum2Dec ( "3c",16 ) );
3.5 任意进制转换
思路:当前进制先转换为十进制数,十进制数转换为目标进制
function anyDecimalConversion (num,srcDec,destDec ) {
//srcDec转换为十进制的数
let decNum = anyNum2Dec(num,srcDec);
//十进制的srcDec 转换为 destDec进制数
return dec2AnyNum(decNum,destDec);
}
验证:
console.log ( anyDecimalConversion ( "abcde", 16,8 ) )