表示式
首先明白中缀、后缀、前缀的表示:
中缀表达式:a+b
前缀表达式(波兰式):+ab
后缀表达式(逆波兰式):ab+
表达式转换
中缀转后缀和中缀转前缀
原则:每遇到两个操作数,一个运算符就把他们用括号扣起来(括号部分可视为一个操作数)
我这里手打了:图看着不清楚
比如
- 原程序 (a+b)*c+d-(e+g)*h
- 可以加括号了,二个操作数一个运算符
- ((a+b)*c) + d - ((e+g)*h)
- (((a+b)*c) +d) - ((e+g)*h)
- ((((a+b)*c) +d) - ((e+g)*h))
接着将运算符移到所在括号前面(不要一次移动多层)
-
- 前移运算符到它所在的括号前面:
-
((((a+b)*c) +d) - ((e+g)*h))
-
(+(*(+(ab)c)d)- *(+(eg)h))
-
-(+(*(+(ab)c)d) *(+(eg)h))
-3. 去掉括号
-+*+abcd *+egh
这是前缀的,转换为后缀就转移到括号
后面
就行了。
比如下面:
前缀转中缀和后缀转中缀
原则
:前缀表达式是将中缀表达式运算符放在前面,因此回转时需要从右向左
扫描前缀表达式,每遇到两个操作数一个运算符
就把运算符放到两个操作数中间
。有的时候可能会连续遇到三个及以上的操作数,则继续向前找,找到和运算匹配的最近的两个操作数即可
比如:
- 原程序: -+*+abcd * +egh
- 每次遇到二个操作数一个运算符就把运算符放二个数中间,从后向前扫描
- -+*+abcd * +e
gh
,但是操作符还隔着一个数,继续往后数,找二个最近的数目 - -+*+abcd *
+eg
h ,暂时忽略h。然后这时候最近的+eg,构成,+放他们中间 - -+*+abcd *
(e+g)
h - -+*+abcd
* (e+g) h
- -+*+abcd
((e+g) *h)
- -+*
(a+b)
cd ((e+g) *h) - -+
((a+b)*c)
d ((e+g) *h) - -
(((a+b)*c)+d)
((e+g) *h) (((a+b)*c)+d) -((e+g) *h)
- 去掉外部括号
- (a+b)*c+d-(e+g)*h
对于后缀转中缀,和前缀转中缀实则是一样的,只不过后缀转中缀的时候需要
从左向右扫描
栈实现
现在我们来学习用栈如何实现这些操作
后/前 缀转中缀
首先我们学习简单的后缀转中缀:
因为他们是从左从右遍历的,所以跟栈很像。
用栈实现后缀表达式的计算:
- ①从左往右扫描下一个元素,直到处理完所有元素
- ②若扫描到操作数则压入栈,并回到①;
- 否则执行③ ③若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到①
如下图:
这时候我们要从左向右扫描,开始扫描到AB+,知道扫描到+停止,弹出二个栈顶元素,这里要注意,先出栈的是右操作数B
,然后执行运算符操作
。。。
最后
前缀跟后缀相反,从右向左扫描,先出栈的是左操作数
中缀转 后\前缀
1、 中缀转后缀
需要二个栈
运算方法:
从左到右
处理各个元素,直到末尾。
可能遇到三种情况:
- ① 遇到
操作数
。直接加入后缀表达式。 - ② 遇到
界限符
。遇到“(”
直接入栈
;遇到“)”
则依次弹出栈内运算符
并加入后缀表达式
,直到 弹出“(”为止
。注意:“(”不加入后缀表达式。
- ③ 遇到
运算符
。依次弹出栈中优先级高于或等于当前运算符的所有运算符
,并加入后缀表达式
, 若碰到“(” 或栈空则停止
。之后再把当前运算符入栈
按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,加入后缀表达式。
举例:以A+B-C*D/E+F 为例
- 遇到操作数 A入栈,运算符+ 优先级最高 ,入另一个栈
- 遇到操作数B,入栈。
- 遇到运算符- ,优先级跟+相比相同,依次弹出栈中优先级高于等于-的。+弹出。
- 然后遇到操作数C,入栈
- 遇到运算符* ,*比-优先级高,所以不弹出。
- 遇到操作数D,入栈。遇到运算符/,/跟优先级相同,弹出,/入栈
- 遇到操作数E,入栈。遇到操作符 +,/*优先级跟+相同或高,弹出。遇到操作数F,入栈
- 最后就剩个+,弹出。结果为
上面是没(),要是有呢
举例:A + B * (C - D) – E / F
- 遇到操作数A,入表达式。遇到+,入栈。
- 遇到B,入表达式。遇到*,栈中没有比他高或相同的,不弹出。
- 遇到界限符( , 遇到(直接入栈
- 遇到C,入表达式。遇到-,但是这时候有界限符(,只有遇到)时候出栈。
- 遇到D,入表达式。遇到),依次弹出运算符.- * + 。(
注意.()不入表达式
) - 遇到E,入表达式,遇到-,此时栈内只有它
- 遇到/,入栈。遇到F入表达式。
- 最后到头了,把当前运算符入表达式,结果如下:
2、 中缀转前缀
跟前面的中缀转后缀一样从左往右扫描,但是弹出的运算符放在表达式的前面
这样算是基本的概念弄懂了,但是代码如何实现还是没搞。
详细的代码见我的C语言实现专栏的———栈的应用—表达式求值(代码实现)