栈实现计算器操作(二)—中缀表达式转后缀表达式

一些思考…

上一篇文章中,我们在遇到与符号栈栈顶优先级相同的符号相同或不变的符号时,会进行数字栈和符号栈分别弹栈→运算→压栈的操作,这是为什么呢?为什么不可以不弹栈运算,等到计算式扫描完成之后再统一进行弹栈运算呢?

—这种算法看似简化了时间复杂度,但是会遇到运算顺序的问题。
考虑下面两种情景:

  • 1-2-3=?: 扫描完成后,如果按照先压栈,到最后统一弹栈的方法,我们的数字栈为[1,2,3], 符号栈为[-,-]。此时运算结果为: 2-3=-1, 1-(-1)=2. 显然错误
  • 1/2/3=?:扫描完成后,运算顺序实则为 1/(2/3)=3/2,同样错误

为什么存在这种问题呢?很简单,最后弹栈的操作改变了运算的顺序。在接下来的后缀表达式转换中同样存在一个问题

中缀→后缀

思路

将思想“遇到优先级相同或更低的元素直接计算,遇到优先级更高的不进行运算”的思想转化成一个表达式,根据运算该表达式得到最终值

方法

换汤不换药,但是后缀表达式的突出优点是,没有括号!!,我们这次考虑中缀表达式中存在符号的情景,来体会后缀表达式的优越性╰(°▽°)╯

  1. 建立一个栈缓存结构
  2. 遇到数字直接输出
  3. 遇到符号,如果栈为空则先压栈,如果不为空,则比较栈顶元素和该符号的优先级:
    3.1如果该符号优先级较大,则直接将该符号压入栈中
    3.2 如果该符号优先级和栈顶符号优先级相同或更小,则先弹出栈顶元素,输出,再将该符号压栈
    3.3 如果栈顶为括号,则不弹栈
  4. 遇到左括号 ( 则直接压栈
  5. 遇到右括号 **)**则输出所有栈内符号,直到遇到左括号( 注意左右括号都不输出到表达式中

一个栗子

中缀表达式 (3-5) * (6+17 * 8)/ 3
按照上面的方法:

  1. 左括号压栈
  2. 3输出
  3. 负号“-”压栈
  4. 5输出
  5. 遇到右括号—弹栈 表达式为“35-”
  6. 遇到乘号“*”,压栈
  7. 遇到左括号,压栈
  8. 6输出
  9. 加号“+” ,此时栈顶为括号,按兵不动
  10. 17输出
  11. 遇到乘号”*“,此时栈顶为加号,直接压栈
  12. 8输出
  13. 右括号,弹栈!此时表达式为:3 5 - 6 17 8 * +, 栈中只有一个乘号
  14. 遇到除号“/”,弹出乘号,压入除号
  15. 输出3
  16. 输出除号,最终表达式为: 3 5 - 6 17 8 * + * 3/

后缀表达式的运算

后缀表达式的计算就很简单了—
建立一个栈缓存结构,遇到数字压栈, 遇到符号则弹出栈顶两个元素进行运算,再存入栈中。

第二个栗子

上一个栗子中的表达式: 3 5 - 6 17 8 * + * 3/

  1. 存入3,5
  2. 遇到“-”,弹出3,5,3-5=-2. 压入-2
  3. 压入6,17,8
  4. 遇到“”,弹出 17,8,178=136, 压入136
  5. 遇到“+”,弹出6,136, 6+136=142,压入142
  6. 遇到“*”,弹出-2,142,(-2)*142=-284
  7. 压入3
  8. 遇到“/”,弹出-284,3,-284/3=-94.67

与中缀表达式运算结果相同。

代码

懒得写了,时间复杂度和空间复杂度均为O(n).

后记

很经典的题目,但是很有意思,思维要严谨,寻找其中的规律。

猜你喜欢

转载自blog.csdn.net/weixin_48711154/article/details/114328118