中缀表达式,后缀表达式以及它们的转换

先说一说中缀表达式。

中缀表达式也就是我们常用常说的算术表达式,像5*3,   3+4*6,  (4+2)/6,(4-1)*(21+4) 这些都是中缀表达式。中缀表达式的特点是运算符在被运算的两个数中间。

 中缀表达式的运算对我们来说并不难,简单的中缀表达式我们小学就会了。但对于电脑来说,运算中缀表达式却并不简单。电脑不懂加减乘除的优先级,如果再加几个括号套过去套过来,只会把电脑搞的不要不要的~

这时候,我们就需要一种优秀的方法来解决这个问题了。于是就有了后缀表达式。

顾名思义,后缀表达式就是运算符在被运算的两个数后面。像5*3写成后缀表达式就是53*,4*2+3就是42*3+。后缀表达式没有括号,运算符也没有优先级,所有运算都是从左往右的。

后缀表达式的运算较为简单,从左往右依次读取,如果读到运算符,就把运算符前两个数字执行相应运算,将结果保存到这个位置。比如4 2 * 3 +,先从左往右读取,第三个遇到*,就把*前面的4和2拿出来相乘,得到8,把8放回去,后缀表达式就变成了8 3 +,再次读取到+,8加上3等于11,就得到了4 2 * 3 +这个后缀表达式的值为11.

后缀表达式没有优先级,括号优先级这些都体现在它的存放顺序中,它存放的顺序直接决定了运算的顺序。中缀表达式3+4*6可以表示成3 4 6 * +,也可以更直观地表示成4 6 * 3 +。像中缀表达式(4+2)/6表示成后缀表达式就是4 2 + 6 /

电脑运算后缀表达式就很方便了,只需要从左往右跑一遍就可以了,而不需要像我们运算中缀表达式那样跳过去跳过来的。如果我们要用电脑处理中缀表达式,可以先将中缀表达式转化为后缀表达式。


接下来就是重点难点了,中缀转后缀。

中缀转后缀要用到栈。

1.先写简单的中缀转后缀,一位数的不包含括号的中缀表达式转换:

将中缀表达式先保存到一个字符串a,再创一个字符串b用于储存产生的后缀表达式,同时还需要一个用于存运算符的栈c。

这里的运算符有个优先级的概念,有必要先说一下。每个运算符的优先级不同,我简单归纳了一下:


+-*/()
2233140

这里有个#号不是运算符,后面用的时候再说。

初始b和栈c都为空,a里面有一个中缀表达式。然后从左往右依次读取中缀表达式a的每一位,a[i]如果是数字就直接存进字符串b这里的数字都是一位数),如果是运算符就和栈顶元素比较,如果这个运算符的优先级大于或等于栈顶运算符的优先级,就把栈顶运算符取出来放进b字符串里面,然后再用该运算符a[i]继续和栈顶运算符进行比较,重复上面的操作,一直到找到优先级低于它的运算符或者栈为空。从左往右一直把a字符串跑完一遍后,b里面已经有一部分后缀表达式了,栈c里面可能还有一部分运算符。那么,我们接下来只需要把栈c里面的运算符倒进b里面就行了,也就是把栈c的元素依次出栈并存到字符串b里面。这样一个后缀表达式b就完成了。

这里有个小技巧,可以在开始前先朝栈c里面放一个字符#,字符#的优先级是最低的,没有运算符能把它弹出来。这样判断的时候就不用判断是否为空栈了。

 实战转换一下3*6+3。注意这里的数字都是以字符的形式存的,所以运算的时候要减去个0字符。

首先创字符串a,b和栈c:

字符串a a[i](操作的字符) 操作字符串b 栈c
3*6+3
33进b3NULL
3*6+3
**进c3*
3*6+3
66进b3 6*
3*6+3
+*的优先级大于+,弹出*到b,c为空,+进c3 6 *+
3*6+3
33进b3 6 * 3 +

a中处理完了将c中元素倒入b3 6 * 3 +NULL
 

得到了它的后缀表达式为3 6 * 3 +

这是最简单的一种中缀转后缀了,基础理解好了后面就好说了。

2.然后就是有括号的中缀表达式,例如6*(4+2)/2

依然是从左往右读,其他处理方式也一样,只是两个括号处理方式不同。读到左括号(不用判断直接存进栈c,不把其他运算符弹出栈。如果读到右括号) 不用进栈,直接一个个把栈c的运算符出栈到b里面,直到遇到到左括号( ,然后把左括号出栈扔了。继续往后读a[i]。

6*(4+2)/2算一遍:

字符串a a[i](操作的字符) 操作  字符串b  栈c
6*(4+2)/2
66进b6NULL
6*(4+2)/2
**进c6*
6*(4+2)/2
((直接进c6*(
6*(4+2)/2
44进b6 4*(
6*(4+2)/2++进c6 4*(+
6*(4+2)/222进b6 4 2*(+
6*(4+2)/2)取栈c的栈顶+,+进b,再取栈顶(,直接删除6 4 2 +*
6*(4+2)/2/*的优先级等于/,*进b,c栈空,/进c6 4 2 +/
6*(4+2)/222进b6 4 2 + * 2*/
 a处理完毕c倒入b中6 4 2 + * 2 /NULL






所以,6*(4+2)/2的后缀表达式为6 4 2 + * 2 /

3.然后再说多位数的。比如32+45*12这种。

关键是题目中的数字是以字符的形式储存的,并不是他们真正的值。

这里有两种方法解决,一种是读取的时候如果为连续数字,则直接乘十往后加,也就是加出它真实的数字。比如32,先读取3,然后读取2,因为是连续数字,所以3*10+2=32。这种方法比较方便,但应用实在有限,因为是字符类型保存的,所以保存的值的大小不能超过256。并且这个数字还可能和运算符的ascll码相同,导致最后当成了运算符处理。所以这方法其实没什么卵用~

第二种是普遍方法,更利于中缀转后缀后输出。简单说就是在后缀表达式的每个数字完了后加上一个#,这样会让b字符串变成类似这样的样子:3 2 # 4 5 # 1 2 # * /  。这样输出的时候还需要稍作处理再输出。

还是以32+45*12为例写一下吧:

字符串a a[i](操作的字符) 操作 字符串b 栈c
32+45*12
33进b3NULL
32+45*1222进b3 2NULL
32+45*12++不为数字,#进b,+进c3 2 #+
32+45*1244进b3 2 # 4+
32+45*1255进b3 2 # 4 5+
32+45*12**不为数字,#进b,*进c3 2 # 4 5 #+*
32+45*1211进b3 2 # 4 5 # 1+*
32+45*1222进b3 2 # 4 5 # 1 2+*

a处理完了最后一个为数字,#进b,c倒入b 3 2 # 4 5 # 1 2 # * + NULL


写了几个小时,终于写完了~~

累~

字符串a a[i](操作的字符) 操作 字符串b 栈c
6*(4+2)/2
66进b6NULL
6*(4+2)/2
**进c6*
6*(4+2)/2
((直接进c6*(
6*(4+2)/2
44进b6 4*(
6*(4+2)/2
++进c6 4*(+
6*(4+2)/2
22进b6 4 2*(+
6*(4+2)/2
)取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 +*
字符串a a[i](操作的字符) 操作 字符串b 栈c
6*(4+2)/2
66进b6NULL
6*(4+2)/2
**进c6*
6*(4+2)/2
((直接进c6*(
6*(4+2)/2
44进b6 4*(
6*(4+2)/2
++进c6 4*(+
6*(4+2)/2
22进b6 4 2*(+
6*(4+2)/2
)取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 +*
字符串a a[i](操作的字符) 操作 字符串b 栈c
6*(4+2)/2
66进b6NULL
6*(4+2)/2
**进c6*
6*(4+2)/2
((直接进c6*(
6*(4+2)/2
44进b6 4*(
6*(4+2)/2
++进c6 4*(+
6*(4+2)/2
22进b6 4 2*(+
6*(4+2)/2
)取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 +*
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值