学习javascript 数据结构 之 栈

285 阅读3分钟

概述

栈是一种特殊的线性表,仅能够在栈顶进行操作,有着先进后出(后进先出)的特性。

如何实现一个栈

从数据存储的角度看,实现栈的方式有2种:一种是以数组作基础,一种是以链表作基础。

定义一个类 Stack,实现以下几个函数:

  • push 添加一个元素到栈顶
  • pop 弹出栈顶元素
  • top 返回栈顶元素(不是弹出)
  • isEmpty 判断栈是否为空
  • size 返回栈里元素的个数
  • clear 清空栈

以数组实现一个栈

function Stack(){
    var items = []
    
    // 向栈压入1个元素
    this.push = function(item){
       items.push(item)
    }
    // 把栈顶的元素弹出
    this.pop = function(){
        return items.pop()
    }
    
    // 返回栈顶元素
    this.top = function(){
        return items[items.length-1]
    }
    
    // 返回栈是否为空
    this.isEmpty = function(){
        return items.length === 0
    }
    
    // 返回栈的大小
    this.size = function(){
        return items.length
    }
    
    // 把栈里的元素清空
    this.clear = function(){
        items = []
    }
}

以链表实现一个栈

LinkList 链表的实现,传送门

function Stack(){
    var linklist = new LinkList()

    // 从栈顶添加元素
    this.push = function(item){
        linklist.append(item)
    }

    // 弹出栈顶元素
    this.pop = function(){
        return linklist.removeTail()
    }

    // 返回栈顶元素
    this.top = function(){
        return linklist.tail()
    }

    // 返回栈的大小
    this.size = function(){
        return linklist.length()
    }

    // 判断是否为空
    this.isEmpty = function(){
        return linklist.isEmpty()
    }

    // 清空栈
    this.clear = function(){
        linklist.clear()
    }
}

题目练习

合法括号

下面字符串中包含小括号,编写一个函数判断字符串中的括号是否合法。合法条件是:括号成对出现。

示例:

sdf(ds(ew(we)rw)rwqq)qwewe 合法

(sd(qwqw)sd(sd)) 合法

()()sd()(sd()fw))( 不合法

思路

  1. 遍历字符串的每个字符。
  2. 遇到左括号,就把左括号压入栈中。
  3. 遇到右括号,先判断栈是否为空,为空说明没有左括号与之对应则字符串括号不合法。如果栈不为空,则把栈顶元素移除,将这对括号抵消掉。
  4. 当遍历结束后,如果栈为空,就说明所有的左括号都抵消掉了,如果栈里还有元素,则说明缺少右括号,字符括号不合法。

代码:

function isLegalBrackets(str){
    var stack = new Stack()
    
    for(var i=0, len=str.length; i< len; i++){
        var item = str[i]
        if(item === '('){
            stack.push(item)
        }else if(item === ')'){
            if(stack.isEmpty()){
               return false
            }else{
                stack.pop()
            }
        }
    }
    return stack.size() === 0
}

console.log('sdf(ds(ew(we)rw)rwqq)qwewe')
console.log('(sd(qwqw)sd(sd))')
console.log('()()sd()(sd()fw))(')
计算逆波兰表达式

逆波兰表达式(后缀表达式),它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)(c+d) 转换为 ab+cd+

示例:

["4","13","5","/","+"] 等价于 (4+(13/5))=6

["10","6","9","3","+","-11","","/","","17","+","5","+"] 等价于((10*(6/((9+3)*-11)))+17)+5

思路

  1. 遍历数组,进行分类。
  2. 如果元素不是 + - * / 中的某一个,就压入栈中。
  3. 如果元素是 + - * / 中的某一个,则从栈里连续弹出2个元素,并对这2个元素进行计算,将计算结果压入栈中。
  4. 遍历结束后,栈只有一个元素,这个元素就是整个表达式的计算结果。

代码

function calcExp(exp){
    var stack = new Stack()
    for(var i=0, len= exp.length; i < len; i++){
        var item = exp[i]
        
        if(['+','-','*','/'].includes(item)){
            // 栈顶弹出2个元素
            var value1 = stack.pop()
            var value2 = stack.pop()
            
            // 拼成表达式
            var expStr = value2 + item + value1
            
            // 计算并取整
            var result = parseInt(eval(expStr))
            // 将计算结果压入栈中
            stack.push(result.toString())
        }else{
            stack.push(item)
        }
    }
    return stack.pop()
}

console.log(["4","13","5","/","+"])