基本概念
在我们的现实生活中,用的最多的是中缀表达式。所谓中缀表达式,是指表达式的运算符在运算元的中间。例如在表达式
a+b
中运算元有两个,即 a 和
但是中缀运算符不能很好地表征运算的次序。例如对于表达式
如果单纯地从表达式来看,我们无法确切地知道到底是先执行加法运算还是先执行乘法运算。当然,我们按照约定俗成的规矩知道应该先执行乘法,再执行加法。因为乘法的优先级比较高。
为了让计算机能够准确地处理诸如 a+b∗c 这样的表达式,我们需要在设计代码时告诉程序表达式执行的顺序。可是,这样的设计非常复杂。因为在现实生活中,我们要考虑的运算符种类繁多,不同的运算符具有不同的优先级。而且,我们在定义表达式时,还会使用括号来显式地规定运算次序。这就使得运算符实现的逻辑更加复杂。
为了设计出一套便于计算机处理的表达式,便有了后缀表达式的概念。所谓后缀表达式,是指表达式的运算符在运算元的末尾。例如中缀表达式
a+b
对应的后缀表达式为
ab+
中缀表达式到后缀表达式的转换
后缀表达式的基本语法规则为
<operand1><operand2><op>
<script type="math/tex; mode=display" id="MathJax-Element-9">
</script>
这里的 <operan1> <script type="math/tex" id="MathJax-Element-10"> </script>和 <operan2> <script type="math/tex" id="MathJax-Element-11"> </script>是两个运算元, <op> <script type="math/tex" id="MathJax-Element-12"> </script>是运算符。其中运算元可以是数字,也可以是一个后缀表达式。这样形成了一个递归的定义,所以可以表示出各种复杂的表达式。
注意
我们这里考虑的只是二元运算,对于三元运算,其后缀表达式的语法规则为
<operand1><operand2><operand3><op><script type="math/tex; mode=display" id="MathJax-Element-13"> </script>在一个后缀表达式可以同时存在一元、二元和多元运算符,并不会增加解析的难度。
- 我们提供的示例仅考虑二元运算。
- 我们考虑了中缀表达式,后缀表达式。大家很容易想见还有一个前缀表达式。它的实现和功能和后缀表达式完全类似,故不再详细讨论。
接下来通过一些加减乘除四则运算,来分析中缀表达式到后缀表达式的转化过程。
例. 考虑如下表达式
a+b−c
为将其转化为后缀表达式,首先通过括号显式地表达出它的运算次序,即
(a+b)−c
然后将最外层的减法 − 运算转化为后缀表达式,即
注意,这里的减法运算共两个运算元即 (a+b) 和 c ,但是
(ab+)c−
最后,由于后缀表达式中括号没有意义,故可以去除。于是得到
ab+c−
例. 考虑如下更复杂的表达式
a+b∗c+(d∗(e−f))/g−(h−i∗j)
首先添括号,得
((a+(b∗c))+((d∗(e−f))/g))−(h−(i∗j))
转化最外层的运算得
((a+(b∗c))+((d∗(e−f))/g))(h−(i∗j))−
最外层的减号运算符有两个运算元,即 ((a+(b∗c))+((d∗(e−f))/g)) 和 (h−(i∗j)) 。其中 ((a+(b∗c))+((d∗(e−f))/g)) 的转化过程为
((a+(b∗c))+((d∗(e−f))/g))↓((a+(b∗c))((d∗(e−f))/g))+↓((a(b∗c)+)((d∗(e−f))/g))+↓((a(bc∗)+)((d∗(e−f))/g))+↓((a(bc∗)+)((d∗(e−f))g/))+↓((a(bc∗)+)((d(e−f)∗)g/))+↓((a(bc∗)+)((d(ef−)∗)g/))+↓abc∗+def−∗g/+
而表达式 (h−(i∗j)) 可以转化为
hij∗−
这样,表达式
((a+(b∗c))+((d∗(e−f))/g))(h−(i∗j))−
最终转化为
abc∗+def−∗g/+hij∗−−
表达式转化到这一步,我们人已经很难直接看出其运算过程了。但是它对于计算机来说,却非常方便处理。