c语言中缀表达式求值_中缀转后缀(逆波兰)表达式的粗浅理解

从书上看到的讲起

最近(半年内 )在看《大话数据结构》,上个星期在栈这一节看到了后缀表达式用于计算的神奇力量。于是用Python试着实现了一下(功底太差,导致花了很长时间)。后缀表达式求值很容易实现,基本就是进栈、出栈和求值,简单一个函数就搞定了。然而中缀转后缀表达式的规则,书上写的似乎有些疏漏。

830a637dc8f483bd485ade461ab4442f.png
后缀表达式求值规则(《大话数据结构》)

287149775968833cb053bab9797359b3.png
中缀转后缀规则(《大话数据结构》)

当尝试了之后发现,上面的描述没有给出若被遍历的符号与栈顶符号同优先级该如何处理。其次,似乎只有当欲右括号时,才应将栈中左括号之前的符号全部出栈。尝试在Bing搜了些资料,没有找到想要的东西,于是在B站找了找,发现两个视频:

  • 中缀转后缀表达式(逆波兰式) 转 前缀表达式(波兰式)8分钟速成手工算法 数据结构栈 https://www.bilibili.com/video/BV1aJ411i7G7
  • 中缀表达式转后缀表达式 | 栈 https://www.bilibili.com/video/BV15g4y187sz

前一个视频可以加深对于后缀表达式的理解,后一个视频给出了具体的算法。

0cca88dc46831af41df37a9ab5980bb4.png
后缀表达式的算法

而这个算法就和我尝试的结果比较吻合,遇优先级相同的时候,也应该输出栈内符号。

然后说说我的理解

通过这些资料和对实现的尝试,我也对后缀表达式的原理有了一点浅显的理解,遂记之以备忘。

在中缀转后缀的算法中,我们会遇到三个元素:数字、运算符和括号,遍历过程中,遇到数字直接输出,而利用栈来比较的是运算符和括号,所以实际上我们是通过比较运算符和括号来确定最终的运算顺序。下面通过几个例子来说明。

  • 例 1

中缀:a+b

对于这个中缀表达式,下面给出每一步比较符号的过程。其中最左边为当前输出的表达式。用中括号[]表示栈,右边是栈顶,栈的右边是当前遍历到的符号。因为遇到数字直接输出,而一个数字后面一般跟一个符号,所以将两步遍历写在一起。

在遍历中,首先遇到数字a,将其直接输出,此时栈为空,然后遍历到加号,当前的状态是
a [] +
----- -----
加号入栈,然后遍历到数字b,将其直接输出,当前的状态是
ab [+]
----- -----
没有其他的符号,将栈中符号输出,于是得到最终的表达式
ab+ []

其中a和b可以看作是其他表达式的运算结果,比如下例。

  • 例 2

中缀:a+c*d

运算过程是:

直接输出a,栈为空,遍历到加号
a [] +
----- -----
加号入栈,直接输出c,遍历到乘号
ac [+] *
----- -----
乘号的优先级比栈顶符号高,所以乘号入栈,直接输出d
acd [+*]
----- -----
没有其他符号,栈内符号依次出栈,于是得到最终输出:acd*+

对于中缀表达式来说,由于乘法的优先级更高,所以要先计算c*d。这里可以将 c*d看作一个整体,相当于上一例中的b,即a+b,其中 b=c*d。

也就是说,我们可以这样看:

中缀          后缀
a + c * d     a c d * +
|   |_b_|     | |_b_| |
|__a+b__|     |__ab+__|
  • 例 3

中缀:a+c+d

这一例中,前后两个符号的优先级相同,所以应该从左到右顺序求值。因为没有什么特别之处,所以就不作过多说明,快速的给出过程:

a [] +
----- -----
ac [+] +
----- -----
优先级相同,栈顶符号出栈,然后加号入栈
acd+ [+]
----- -----
acd++ []
  • 例 4

中缀:a-c+d

先给出过程:

a [] -
----- -----
ac [-] +
----- -----
由于加号与栈顶符号优先级相同,所以栈顶符号出栈,然后加号入栈;接下来遍历遇到数字d,直接输出。
ac-d [+]
----- -----
没有其他符号,栈内符号依次出栈。
ac-d+ []

这一例就有点不同了,因为两个符号的优先级相同,运算顺序必须从左到右,即(a-c)+d,将a-c视为一个整体;而如果不小心变成a-(c+d),将c+d视为一个整体,就产生错误了。

a - c + d     a c - d +
|___|   |     |___|   |
|_______|     |_______|

              错误(愿你不会遇到):
              a c d + -
              | |___| |
              |_______|

通过上面4个例子可以看到,对于一个长的表达式 a+c*d 或 a + b + c 等,通过计算优先级高的部分,或从左往右计算,最终总是会变成类似于 a + b(或a-b,或乘,或除以)的形式。也就是说,表达式中,两个数字和他们的运算符可以看作是一个整体,即一个数字。理解了这一点,应该就容易理解后缀表达式为什么能用来代替中缀表达式求值了。实际上中缀表达式也是如此,每次计算两个数,然后逐渐化为a+b的形式,而中缀表达式不需要括号,求值要方便很多。

吐槽:在知乎发的第一篇文章。写完发现自己的表达能力还很欠缺,而且好像忘了自己要讲什么。anyway,希望有人看到之后会受到启发吧(或者被我弄得更糊涂了)。

p.s 上面提到的B站的两个视频其实很不错的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值