如何计算【3 + 12 * 2 - 2^2】?中缀表达式转后缀表达式

91 阅读2分钟

如果想通过实现算法来计算3 + 12 * 2 - 2^2,第一步需要先把我们熟悉的中缀表达式转成后缀表达式。

思路

首先将输入的中缀表达式转换为一个数组,然后遍历这个数组,对于每个元素进行以下判断和操作:

  • 如果它是一个左括号,就将其压入栈;
  • 如果它是一个右括号,就将栈中的运算符弹出并添加到输出队列,直到遇到左括号;
  • 如果它是一个数字,就直接添加到输出队列;
  • 如果它是一个运算符,就将栈中优先级高于或等于它的运算符弹出并添加到输出队列,然后将它压入栈。

最后,将栈中剩余的运算符弹出并添加到输出队列。

代码实现

const operators = {
  '*': {
    priority: 2,
    associativity: 'left'
  },
  '/': {
    priority: 2,
    associativity: 'left'
  },
  '+': {
    priority: 1,
    associativity: 'left'
  },
  '-': {
    priority: 1,
    associativity: 'left'
  },
  '^': {
    priority: 3,
    associativity: 'right'
  }
}

function infixToRPN(infix) {
  let resultList = []
  let charList = []
  infix = infix.replace(/\s+/g, '')
  infix = infix.replace(/-\d+/g, match => match.replace('-', '#')) // 将负数替换为特殊标记
  infix = infix.split(/([\+\*\/\^\(\)])/).filter(item => item)
  infix = infix.map(item => item.replace('#', '-')) // 将特殊标记替换回负数
  for ( let i = 0; i < infix.length; i++ ) {
    let value = infix[i]
    if (value === '(') {
      // 如果它是一个左括号,就将其压入栈;
      charList.push(value)
    } else if (value === ')') {
      // 如果它是一个右括号,就将栈中的运算符弹出并添加到输出队列,直到遇到左括号;
      let char = charList.pop()
      while (char !== '(' && char) {
        resultList.push(char)
        char = charList.pop()
      }
    } else if (/\d/.test(value)) {
      // 如果它是一个数字,就直接添加到输出队列;
      resultList.push(value)
    } else {
      // 如果它是一个运算符,就将栈中优先级高于或等于它的运算符弹出并添加到输出队列,然后将它压入栈。
      let len = charList.length
      let char = charList[len - 1]
      while (len && operators[char] && operators[char].priority >= operators[value].priority && operators[char].associativity === 'left') {
        resultList.push(charList.pop())
        len = charList.length
        char = charList[len - 1]
      }
      charList.push(value)
    }
  }

  // 最后,将栈中剩余的运算符弹出并添加到输出队列。
  let char = charList.pop()
  while (char) {
    resultList.push(char)
    char = charList.pop()
  }
  return resultList
}

写在最后

该算法的最关键的点,理解运算符的入栈规则,需要先把优先级更高的运算符先输出,因为就符合我们日常计算的乘法的优先级高于加法的规则。

还有比较重要的点,就是计算的公式中含有负数的时候,需要先把负数的符号先替换成别的特殊字段,根据操作符剪切字符串成数组的时候才不会把负数处理成整数和-号。转成数组后,再把特殊字符替换回负号。如果你们有更好的实现方法,欢迎评论区留言,大家一起学习交流~~