栈的应用—表达式转换和求值

48 阅读5分钟

表示式

首先明白中缀、后缀、前缀的表示:

中缀表达式a+b

前缀表达式(波兰式)+ab

后缀表达式(逆波兰式)ab+

图片.png


表达式转换

图片.png

中缀转后缀和中缀转前缀

原则:每遇到两个操作数,一个运算符就把他们用括号扣起来(括号部分可视为一个操作数)

我这里手打了:图看着不清楚

比如

  • 原程序 (a+b)*c+d-(e+g)*h
  1. 可以加括号了,二个操作数一个运算符
  • ((a+b)*c) + d - ((e+g)*h)
  • (((a+b)*c) +d) - ((e+g)*h)
  • ((((a+b)*c) +d) - ((e+g)*h))

接着将运算符移到所在括号前面(不要一次移动多层)

    1. 前移运算符到它所在的括号前面:
  • ((((a+b)*c) +d) - ((e+g)*h))

  • (+(*(+(ab)c)d)- *(+(eg)h))

  • -(+(*(+(ab)c)d) *(+(eg)h))

-3. 去掉括号

-+*+abcd *+egh

这是前缀的,转换为后缀就转移到括号后面就行了。

比如下面:

图片.png


前缀转中缀和后缀转中缀

原则:前缀表达式是将中缀表达式运算符放在前面,因此回转时需要从右向左扫描前缀表达式,每遇到两个操作数一个运算符就把运算符放到两个操作数中间。有的时候可能会连续遇到三个及以上的操作数,则继续向前找,找到和运算匹配的最近的两个操作数即可

比如:

  • 原程序: -+*+abcd * +egh
  • 每次遇到二个操作数一个运算符就把运算符放二个数中间,从后向前扫描
  • -+*+abcd * +egh ,但是操作符还隔着一个数,继续往后数,找二个最近的数目
  • -+*+abcd * +egh ,暂时忽略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

对于后缀转中缀,和前缀转中缀实则是一样的,只不过后缀转中缀的时候需要从左向右扫描

图片.png


栈实现

现在我们来学习用栈如何实现这些操作

后/前 缀转中缀

首先我们学习简单的后缀转中缀:

因为他们是从左从右遍历的,所以跟栈很像。

用栈实现后缀表达式的计算:

  • ①从左往右扫描下一个元素,直到处理完所有元素
  • ②若扫描到操作数则压入栈,并回到①;
  • 否则执行③ ③若扫描到运算符,则弹出两个栈顶元素,执行相应运算,运算结果压回栈顶,回到①

如下图:

图片.png

这时候我们要从左向右扫描,开始扫描到AB+,知道扫描到+停止,弹出二个栈顶元素,这里要注意,先出栈的是右操作数B,然后执行运算符操作

图片.png

图片.png

。。。

最后

图片.png

前缀跟后缀相反,从右向左扫描,先出栈的是左操作数


中缀转 后\前缀

1、 中缀转后缀

需要二个栈

运算方法:

左到右处理各个元素,直到末尾。

可能遇到三种情况:

  • ① 遇到操作数。直接加入后缀表达式。
  • ② 遇到界限符。遇到“(”直接入栈;遇到“)”则依次弹出栈内运算符加入后缀表达式直到 弹出“(”为止注意:“(”不加入后缀表达式。
  • ③ 遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式, 若碰到“(” 或栈空则停止。之后再把当前运算符入栈

按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,加入后缀表达式。

举例:以A+B-C*D/E+F 为例

  • 遇到操作数 A入栈,运算符+ 优先级最高 ,入另一个栈

图片.png

  • 遇到操作数B,入栈。

图片.png

  • 遇到运算符- ,优先级跟+相比相同,依次弹出栈中优先级高于等于-的。+弹出。
  • 然后遇到操作数C,入栈

图片.png

  • 遇到运算符* ,*比-优先级高,所以不弹出。

图片.png

  • 遇到操作数D,入栈。遇到运算符/,/跟优先级相同,弹出,/入栈

图片.png

  • 遇到操作数E,入栈。遇到操作符 +,/*优先级跟+相同或高,弹出。遇到操作数F,入栈

图片.png

  • 最后就剩个+,弹出。结果为

图片.png


上面是没(),要是有呢

举例:A + B * (C - D) – E / F

  • 遇到操作数A,入表达式。遇到+,入栈。

图片.png

  • 遇到B,入表达式。遇到*,栈中没有比他高或相同的,不弹出。

图片.png

  • 遇到界限符( , 遇到(直接入栈

图片.png

  • 遇到C,入表达式。遇到-,但是这时候有界限符(,只有遇到)时候出栈。

图片.png

  • 遇到D,入表达式。遇到),依次弹出运算符.- * + 。(注意.()不入表达式)
  • 遇到E,入表达式,遇到-,此时栈内只有它

图片.png

  • 遇到/,入栈。遇到F入表达式。

图片.png

  • 最后到头了,把当前运算符入表达式,结果如下:

图片.png


2、 中缀转前缀

跟前面的中缀转后缀一样从左往右扫描,但是弹出的运算符放在表达式的前面

图片.png


这样算是基本的概念弄懂了,但是代码如何实现还是没搞。

详细的代码见我的C语言实现专栏的———栈的应用—表达式求值(代码实现)