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

先说一说中缀表达式。

中缀表达式也就是我们常用常说的算术表达式,像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。

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


+ - * / ( )
2 2 3 3 1 4 0

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

初始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
3 3进b 3 NULL
3*6+3
* *进c 3 *
3*6+3
6 6进b 3 6 *
3*6+3
+ *的优先级大于+,弹出*到b,c为空,+进c 3 6 * +
3*6+3
3 3进b 3 6 * 3  +

a中处理完了 将c中元素倒入b 3 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
6 6进b 6 NULL
6*(4+2)/2
* *进c 6 *
6*(4+2)/2
( (直接进c 6 *(
6*(4+2)/2
4 4进b 6 4 *(
6*(4+2)/2 + +进c 6 4 *(+
6*(4+2)/2 2 2进b 6 4 2 *(+
6*(4+2)/2 ) 取栈c的栈顶+,+进b,再取栈顶(,直接删除 6 4 2 + *
6*(4+2)/2 / *的优先级等于/,*进b,c栈空,/进c 6 4 2 + /
6*(4+2)/2 2 2进b 6 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
3 3进b 3 NULL
32+45*12 2 2进b 3 2 NULL
32+45*12 + +不为数字,#进b,+进c 3 2 # +
32+45*12 4 4进b 3 2 # 4 +
32+45*12 5 5进b 3 2 # 4 5 +
32+45*12 * *不为数字,#进b,*进c 3 2 # 4 5 # +*
32+45*12 1 1进b 3 2 # 4 5 # 1 +*
32+45*12 2 2进b 3 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
6 6进b 6 NULL
6*(4+2)/2
* *进c 6 *
6*(4+2)/2
( (直接进c 6 *(
6*(4+2)/2
4 4进b 6 4 *(
6*(4+2)/2
+ +进c 6 4 *(+
6*(4+2)/2
2 2进b 6 4 2 *(+
6*(4+2)/2
) 取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 + *
字符串a a[i](操作的字符) 操作 字符串b 栈c
6*(4+2)/2
6 6进b 6 NULL
6*(4+2)/2
* *进c 6 *
6*(4+2)/2
( (直接进c 6 *(
6*(4+2)/2
4 4进b 6 4 *(
6*(4+2)/2
+ +进c 6 4 *(+
6*(4+2)/2
2 2进b 6 4 2 *(+
6*(4+2)/2
) 取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 + *
字符串a a[i](操作的字符) 操作 字符串b 栈c
6*(4+2)/2
6 6进b 6 NULL
6*(4+2)/2
* *进c 6 *
6*(4+2)/2
( (直接进c 6 *(
6*(4+2)/2
4 4进b 6 4 *(
6*(4+2)/2
+ +进c 6 4 *(+
6*(4+2)/2
2 2进b 6 4 2 *(+
6*(4+2)/2
) 取栈c的栈顶元素+,+进b,再取栈顶元素( ,直接删除
6 4 2 + *
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章