什么是栈

先进后出(后进先出)

常见的办法

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

实现栈的逻辑

function Stack() {  const items = []  // 从栈顶增加元素,压栈  this.push = function (item) {    items.push(item)  }  // 弹出  this.pop = function () {    return !this.isEmpty() && items.pop()  }  // 返回栈顶元素  this.top = function () {    return !this.isEmpty() && items[items.length - 1]  }  // 判断是否为空  this.isEmpty = function () {    return items.length === 0  }  // 返回栈里的大小  this.size = function () {    return items.length  }  // 清空栈  this.clear = function () {    items.length = 0  }}

简略练习

1、判断括号是否非法

思路

遍历字符串,当遇到 ( 时,增加一个记号到栈中,示意这是第一对括号的结尾。
当遇到 ) 时,咱们从栈中取出一个记号,示意该括号为一组。
中途如果遇到 无奈pop的时候,则示意短少了 (。间接返回 false。
遍历完结后,咱们判断栈的长度。如果栈空,则示意所有括号都对消掉返回 true。如果长度不为 0,则示意其中短少了 )。返回 false。

代码实现
const str1 = '(12)(323)()123(1))'const str2 = '()(123123)'function isLegal(str) {  const items = new Stack()  for (let i = 0; i < str.length; i++) {    if (str[i] === '(') {      items.push(1)    } else if (str[i] === ')') {      if (items.isEmpty()) return false      else items.pop()    }  }  return items.isEmpty()}console.log(isLegal(str1), isLegal(str2))

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

思路

遍历该数组表达式,将所有数字增加到栈中。
当遇到运算符时,从栈中取出两个数字进行拼接,应用eval进行计算,并将后果从新压栈。持续循环
循环完结后,如果表达式正确会剩下最初一个数值,咱们只须要从栈中取出来返回即可

代码实现
// 4+13/5const exp1 = ['4', '13', '5', '/', '+']const exp2 = ['10', '6', '9', '3', '+', '-11', '*', '/', '*', '17', '+', '5', '+']function calcExp(exp) {  const stack = new Stack()  for (let i = 0; i < exp.length; i++) {    const item = exp[i]    if (['+', '-', '*', '/'].indexOf(item) >= 0) {      const value1 = stack.pop()      const value2 = stack.pop()      const expStr = value2 + item + value1      stack.push(parseInt(eval(expStr)).toString())    } else {      stack.push(item)    }  }  return stack.pop()}console.log(calcExp(exp1))console.log(calcExp(exp2))

3、实现一个有min办法的栈

实现一个栈,除了常见的push,pop办法以外,提供一个min办法,返回栈里最小值。要求工夫复杂度为 O(1)

思路

定义两个栈,一个失常存数据和操作,下文简称栈。另一个存每次的进栈时的最小值,下文简称min栈。
当每次push的时候,将值失常增加到栈中。咱们判断min栈中,如果为空或者min栈顶的数据比增加的值大,那么咱们进行压栈。此时min栈顶就是此次操作中的最小值。
每次pop的时候,栈和min栈失常操作即可。min栈pop一个元素后的栈顶。因为每次push咱们都会往min栈中压入该状态的最小值。此时取栈顶的值,仍旧是该栈中的最小值。

代码实现
function MinStack() {  const stack = new Stack()  const minStack = new Stack()  this.push = function (item) {    stack.push(item)    if (minStack.isEmpty() || minStack.top() > item) {      minStack.push(item)    } else {      minStack.push(minStack.top())    }  }  this.pop = function () {    if (stack.isEmpty()) return false    stack.pop()    minStack.pop()  }  this.min = function () {    return minStack.top()  }}const minStack = new MinStack()minStack.push(3) // [3]console.log(minStack.min()) // 3minStack.push(2) // [3,2]console.log(minStack.min()) // 2minStack.push(5) // [3,2,5]console.log(minStack.min()) // 2minStack.push(-1) // [3,2,5,-1]console.log(minStack.min()) // -1minStack.pop() // [3,2,5]minStack.pop() // [3,2]minStack.pop() // [3]console.log(minStack.min()) // 3// 3// 2// 2// -1// 3

4、中序表达式转后缀表达式

思路

定义一个栈和一个 list 数组。
循环表达式元素。
如果为数字,间接增加到 list 中。
如果为左括号,则压栈。
如果为右括号,则循环栈元素,并顺次弹出栈顶元素到 list 中,直到遇到左括号完结循环。并弹出左括号。
如果为运算符,则判断过后的栈是否为空栈。如果空栈,则将运算符间接增加到空栈中。如果不为空栈则循环该栈,将栈顶的运算符优先级大于等于以后运算符的一次弹出,并增加到 list。直到找到优先级小于以后运算符为止。
将以后运算符压栈。
循环完结后,将栈中剩下的元素,顺次弹出栈顶元素并增加到 list 中。
并返回 list 后果。

代码实现
const priorityMap = {  '+': 1,  '-': 1,  '*': 2,  '/': 2}function infixExpToPostfixExp(exp) {  const stack = new Stack()    const list = []  for (let i = 0; i < exp.length; i++) {    const item = exp[i]    if (!isNaN(item)) {      list.push(item)    } else if (item === '(') {      stack.push(item)    } else if (item === ')') {      while (stack.top() !== '(') {        list.push(stack.pop())      }      stack.pop()    } else {      while (!stack.isEmpty() && ['+', '-', '*', '/'].indexOf(stack.top()) !== -1 && priorityMap[stack.top()] >= priorityMap[item]) {        list.push(stack.pop())      }      stack.push(item)    }  }    while(!stack.isEmpty()) {    list.push(stack.pop())  }  return list}const test1 = ['12', '+', '3'] // 12+3const test2 = ['2', '-', '3', '+', '2'] // 2-3+2const test3 = ['(', '1', '+', '(', '4', '+', '5', '+', '3', ')', '-', '3', ')', '+', '(', '9', '+', '8', ')'] // (1+(4+5+3)-3)+(9+8)console.log(infixExpToPostfixExp(test1))console.log(infixExpToPostfixExp(test2))console.log(infixExpToPostfixExp(test3))