【JavaScript数据结构与算法】栈

1 什么是栈?

栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。栈具有后进先出(LIFO-Last In First Out)的特点。

2 栈的属性/方法

为了记录栈顶元素的位置,同时也为了标记哪里可以加入新元素,使用变量top。
对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。入栈:push(),出栈:pop()。
另一个常用的操作是预览栈顶的元素。pop()虽然可以访问栈顶的元素,但是调用该方法后栈顶的元素也从栈中删除了。所以使用peek()方法,仅仅访问而不删除。
length()方法返回栈内元素个数。
empty()方法返回栈是否为空。
clear()方法清空栈内元素。

3 栈的实现

function Stack(){
    this.dataStore=[];
    this.top=0;
    this.push=push;
    this.pop=pop;
    this.peek=peek;
    this.length=length;
    this.empty=empty;
    this.clear=clear;
}
function push(item){
    this.dataStore[this.top++]=item;
}//不要忘了this.top++
function pop(){
    return this.dataStore[--this.top];
}
function peek(){
    return this.dataStore[this.top-1];
}//体会pop和peek的区别
function clear(){
    delete this.dataStore;
    this.dataStore=[];
    this.top=0;
}
function length(){
    return this.top;
}
function empty(){
    return this.top===0?true:false;
}

4 栈的应用

4.1 数制转换

算法如下:

  1. 最低位为n%b,将此位压入栈。
  2. 使用n/b代替n
  3. 重复步骤1和2,直到n=0且没有余数。
  4. 将栈内元素依次弹出,排列得到转换后的数字字符串形式。
    此算法之针对基数2-9的情况。
function convertNum(num,base){
	var s=new Stack();
    do{
        s.push(num%base);
        num=Math.floor(num/base);
    }while(num>0)//全部压栈
    var convertedStr='';
    while(!s.empty()){
        convertedStr+=s.pop();
    }
    return convertedStr;
}
console.log(convertNum(10,2));//1010

4.2 回文

回文是指这样一种现象:一个单词/短语/数字。从后往前和从前往后写都是一样的。
使用栈可以轻松判断回文,每个字符从左到右压栈,弹出后排列成新的字符串,两者内容相同则是回文。

function IsPalindrome(word){
    var s=new Stack();
    var word=word.toString();
    for(var i=0;i<word.length;i++){
        console.log(word[i]);
        s.push(word[i]);
    }
    var newWord='';
    while(!s.empty()){
        newWord+=s.pop();
    }
    console.log(word,newWord);
    return word==newWord?true:false;
}
console.log(IsPalindrome(1221));//true
console.log(IsPalindrome('hello'));//false

4.3 递归模拟

以阶乘为例

function factorial(n){
    var s=new Stack();
    do{
        s.push(n--);
    }while(n>0)
    var total=1;
    while(!s.empty()){
        total*=s.pop();
    }
    return total;
}
console.log(factorial(5));//120

4.4 练习

4.4.1 括号匹配

栈可以用来判断一个算术表达式中的括号是否匹配。 编写一个函数, 该函数接受一个算术表达式作为参数, 返回括号缺失的位置。 下面是一个括号不匹配的算术表达式的例子: 2.3 + 23 / 12 + (3.14159× 0.24。

function getPos(str){
    var s=new Stack();
   for(var i=0;i<str.length;i++){
       if(str[i]=='('){
        s.push(i);
       }else if(str[i]==')'){
        s.pop();
       }
   }
   console.log('不匹配位置为字符'+s.peek());
}

getPos('2.3 + 23 / 12 + (3.14159× 0.24');//不匹配位置为字符16
  • 关键点:检测到(后push的是i,即括号本身的位置。当且仅当有)出现时才会pop,所以剩下的是没有被匹配的。
4.4.2 佩兹糖果盒

现实生活中栈的一个例子是佩兹糖果盒。 想象一下你有一盒佩兹糖果, 里面塞满了红色、 黄色和白色的糖果, 但是你不喜欢黄色的糖果。 使用栈(有可能用到多个栈) 写一段程序, 在不改变盒内其他糖果叠放顺序的基础上, 将黄色糖果移出。

function removeYellow(s){
    var otherStack=new Stack();
    var yellowStack=new Stack();
    var newStack=new Stack();
    while(!s.empty()){
       if(s.peek()!='yellow'){
        otherStack.push(s.pop());
       }else{
        yellowStack.push(s.pop());
       }
    }
    while(!otherStack.empty()){
        newStack.push(otherStack.pop());
    }
    return newStack;
}
var s=new Stack();
s.push('red');
s.push('orange');
s.push('yellow');
s.push('green');
s.push('blue');
s.push('pink');
s=removeYellow(s);
console.log(s);
  • 关键点:
  1. 原思路:颜色不为黄的时候就将pop的元素加入到新的栈中,最后将该栈中的元素再pop出来给原栈就可以了。问题在于:对颜色为黄的元素也要进行判断处理,否则原栈就永远不会为空,while(!s.isEmpty())也就变成了无限循环,这也是运行程序的时候出现问题的地方。
  2. 值得注意的是,将原栈的所有元素pop出去后,数组本身并不为空,只是top指针为0,如果此时将筛选出来的元素直接添加到原栈中就会出现问题。所以最后还是开辟了一个新栈,所以函数中用了三个栈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值