数据结构与算法 - 栈

栈:

概念

栈又称为 "先进后出" 线性表,只有一端栈顶可以操作,另一端为固定端,称为栈底,

羽毛球盒

实际生活中,羽毛球盒,可以很形象的看成一个栈,只能在一端盒顶进行操作:

数据结构与算法 - 栈_第1张图片

栈的常用方法:

push:添加一个元素到栈顶(相当于向羽毛球桶里放入一个羽毛球)

pop:弹出栈顶元素(从桶里拿出一个羽毛球)

top:返回(return)栈顶元素,不是出栈(看了一眼桶里最顶端的羽毛球)

isEmpty:判断栈是否为空(看下羽毛球是否用完了)

size:返回栈元素的个数。(数一桶里下羽毛球的个数)

clear:清空栈(把桶里羽毛球都倒出来扔掉)

数组实现栈:

function Stack() {
    var mainStack = []
    this.push = function(item) {
        mainStack.push(item)
    }
    this.pop = function() {
        return mainStack.pop()
    }
    this.top = function() {
        return mainStack[mainStack.length - 1]
    }
    this.size = function() {
        return mainStack.length
    }
    this.isEmpty = function() {
        return mainStack.length === 0
    }
    this.clear = function() {
        mainStack = []
    }
}

练习题:

1、判断括号是否是对称的

思路:

(1)我们用栈的思想来解决此问题,首先遍历,碰到左括号直接入栈;

(2)如果碰到右括号,分两种情况,栈是否为空,如果不为空,则从栈顶弹出一个左括号(相当于左右括号抵消掉了);如果为空,说明右括号的数量多于左括号,直接返回false;

(3)遍历完,看下栈中是否有数据,有的话,说明左括号的数量多于右括号,返回false;栈为空,说明对称,返回true。

function isSMP(strParam) {
    var stack = new Stack()
    var len = strParam.length
    for(var i = 0; i < len; i ++) {
        if(strParam[i] === '(') {
            stack.push(strParam[i])
        }else if(strParam[i] === ')') {
            if(stack.isEmpty()) {
                return false
            }else{
                stack.pop()
            }
        }
    }
    return stack.isEmpty()
}
var res = isSMP('(FDS()FD)f')
console.log(res) // true

2、创建一个栈ReturnMinCountStack,除了常见的进栈、出栈的方法以外,写一个求栈最小值的方法,时间复杂度O1

思路:

(1)由于栈的特性"先进后出", 且只能操作栈顶元素,不可以遍历栈中的元素,所以此题需要在下边ReturnMinCountStack栈中,创建2个栈,一个栈存放压入栈的所有元素(存放每次入栈的元素),另一个栈存放最小值(这个栈是为求最小值的方法所准备的)。

(2)元素第一次入栈时,存放最小值的栈,一定是空的,且此元素一定是最小值,因为存放最小值的栈就这一个值;当下一次元素入栈时, 比较此元素是否小于存放最小值的栈的栈顶元素,如果小于,会把此元素压入最小值的栈中;否则,把存放最小值的栈的栈顶元素压入最小值栈中 去,这种方式会一直保持存放最小值的栈的栈顶元素是最小的。

function ReturnMinCountStack() {
  var data_stack = new Stack()
  var min_stack = new Stack()
  this.push = function(item){
    data_stack.push(item)
    if(min_stack.isEmpty() || item < min_stack.top()) {
      min_stack.push(item)
    }else{
      min_stack.push(min_stack.top())
    }
  }
  this.pop = function() {
    data_stack.pop()
    min_stack.pop()
  }
  this.min = function() {
    return min_stack.top() // 返回最小值的栈顶元素
  }
}
var res = new ReturnMinCountStack()
res.push(1)
res.push(10)
res.push(0)
console.log(res.min()) // 0

3、后缀表达式(逆波兰式)运算

逆波兰式(或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后),之所以要把中序表达式转为后缀表达式(逆波兰式),因为逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。

思路:遍历数组,数字直接入栈,如果是运算符,连续弹出2个元素,对元素进行运算,结果压入栈中,最后把计算结弹出。

// 逆波兰式 正常的运算是:6 + 4 / 2,转为后缀表达式就是下边参数形式
function endExpression(arr) {
    var stack = new Stack()
    arr.forEach(ele => {
        if(['/', '-', '+', '*'].indexOf(ele) !== -1) {
            var stckEle_1 = stack.pop()
            var stackEle_2 = stack.pop()
            var result = eval(stackEle_2 + ele + stckEle_1).toString()
            stack.push(result)
        }else{
            stack.push(ele)
        }
    })
    return stack.pop()
}
var res = endExpression([ "6", "4", "2", "/", "+" ])
console.log(res) // 8

 

你可能感兴趣的:(数据结构与算法,数据结构与算法)