逆波兰计算器原理和实现

逆波兰表达式也叫后缀表达式,其特点是运算符在两个运算数字(或表达式)后,例如:3,4 ,+ , 5,x,6 ,-,后缀表达式虽然不利于人的阅读,但是便于计算机处理。
提到后缀表达式也不得不说一下中缀表达式,中缀表达式就是我们最常见的表达式形式,其特点是运算符在两个运算数字(或表达式)之间,例如(3+4)*5-6,中缀表达式符合人类阅读习惯

要实现逆波兰计算器,需要完成两个步骤:
1.将中缀表达式转成逆波兰表达式
2.计算逆波兰表达式
这两个步骤都有现成的算法实现。

中缀表达式转成逆波兰表达式的思路分析:

  1. 初始化两个栈,分别用于存储符号(栈s1)和逆波兰表达式结果(栈s2)
  2. 从左到右扫描中缀表达式
  3. 遇到操作数时,将其压入s2,遇到运算符时,需要分左括号、右括号和±*-三种情况
  4. 如果是左括号“(”,直接将其压入s1;如果是右括号“)”,依次将符号栈s1中的符号弹出并压入s2中,直到遇到左括号“(”为止,再将s1栈顶的“(”弹出;如果是+ -x /,则需要考虑扫描到的运算符与s1栈顶运算符的优先级
  5. 如果扫描到的运算符优先级比s1栈顶运算符优先级高,直接压入s1,否则,s1栈顶的符号弹出,并压入s2,循环步骤5,直到栈顶符号优先级不再比当前符号高,再当前运算符压入s1(这里只比较+ -x /,如果s1栈顶是左括号,则将当前符号直接压入符号栈)
  6. 将s1中剩余元素依次弹出并压入s2

下面以(3+4)*5-6为例,演示一下如何将中缀表达式转成逆波兰表达式:
1.按照以上的步骤,依次将左括号压入s1,3压入s2,+压入s1,4压入s2,如下图:
逆波兰计算器原理和实现
2.接下来是右括号,这里是关键,按照上述原理步骤4,依次将s1中的符号弹出并压入s2中,直到遇到左括号“(”为止,之后再将栈顶的“(”弹出,如下图:
逆波兰计算器原理和实现
3.接下来是* 号,s1栈为空,不用比较优先级,直接压入s1,5压入s2,如下图:
逆波兰计算器原理和实现
4.接下来是-号,由于-号优先级比*低,按照上述原理步骤5,需要将s1栈顶的*弹出,并压入s2,-号压入s1,最后6再压入s2,如下图:
逆波兰计算器原理和实现
5.最后,将s1中的-号弹出并压入s2:
逆波兰计算器原理和实现
最终s2从栈底到栈顶的顺序构成的表达式3,4,+,5,*,6,-就是由(3+4)*5-6转成的逆波兰表达式。

至此,完成逆波兰计算器的第一步已经完成,下面就是如何对逆波兰表达式进行计算。

逆波兰表达式计算原理

  1. 创建一个栈s用于存储计算结果
  2. 依次扫描逆波兰表达式
  3. 如果扫描到数,就将该数压入s
  4. 如果是运算符,就将s栈顶元素和次顶元素弹出,进行计算,计算结果再压入s。计算时注意运算顺序,次顶元素在栈顶元素之前

这个原理其实很好理解,就是扫描逆波兰表达式,如果遇到数就入栈,遇到符号就将栈顶的两个元素弹出来计算,并将计算结果再压入栈中,最后栈中剩余的一个数就是计算结果,这里就不再画图演示了。
完整代码详见github源码地址:https://github.com/ithushuai/calculator