- 数据结构(C语言实现)
- 陈锐等编著
- 2053字
- 2022-05-10 18:02:04
3.2.3 算术表达式求值
表达式求值是程序设计语言编译中的一个基本问题。在编译系统中,需要把人们便于理解的表达式翻译成计算机理解的表示序列,这就可以利用栈的“后进先出”特性实现表达式的转换。
一个表达式由操作数(Operand)、运算符(Operator)和分界符(Delimiter)组成。一般地,操作数可以是常数,也可以是变量;运算符可以是算术运算符、关系运算符和逻辑运算符;分界符包括左右括号和表达式的结束符等。为了简化问题的描述,我们仅讨论简单算术表达式的求值问题。这种表达式只包含加、减、乘、除等四种运算符和左、右圆括号。
计算机编译系统在计算算术表达式的值时,需要先将中缀表达式转换为后缀表达式,然后求解表达式的值。
1.将中缀表达式转换为后缀表达式
例如,一个算术表达式为:
a-(b+c*d)/e
这种算术表达式中的运算符总是出现在两个操作数之间,这种算术表达式被称为中缀表达式。编译系统在计算一个算术表达式之前,要将中缀表达式转换为后缀表达式,然后对后缀表达式进行计算。在后缀表达式中,算术运算符出现在操作数之后,并且不含括号。
上面的算术表达式对应的后缀表达式为:
abcd*+e/-
中缀表达式与后缀表达式相比,具有以下两个特点:
(1)后缀表达式与中缀表达式的操作数出现顺序相同,只是运算符先后顺序改变了。
(2)后缀表达式不出现括号。
说明:由于后缀表达式具有以上特点,所以,编译系统在处理时不必考虑运算符的优先关系。只要从左到右依次扫描后缀表达式的各个字符,当读到的字符为运算符时,对运算符前面的两个操作数利用该运算符运算,并将运算结果作为新的操作对象替换两个操作数和运算符,继续扫描后缀表达式,直到处理完毕。
综上,表达式的运算分为两个步骤:
(1)将中缀表达式转换为后缀表达式。
(2)依据后缀表达式计算表达式的值。
将一个算术表达式的中缀形式转换为相应的后缀形式前,需要先了解算术四则运算的规则。算术四则运算的规则是:
(1)先计算乘除,后计算加减。
(2)先计算括号内的表达式,后计算括号外的表达式。
(3)同级别的运算从左到右进行计算。
如何将中缀表达式转换为后缀表达式呢?设置一个栈,用于存放运算符。依次读入表达式中的每个字符,如果是操作数,则直接输出;如果是运算符,则比较栈顶元素符与当前运算符的优先级,然后进行处理,直到整个表达式处理完毕。这里,约定‘#’作为后缀表达式的结束标志,假设栈顶运算符为ө1,当前扫描的运算符为ө2。
中缀表达式转换为后缀表达式的算法如下:
(1)初始化栈,将‘#’入栈。
(2)如果当前读入的字符是操作数,则将该操作数输出,并读入下一个字符。
(3)如果当前字符是运算符,记作ө2,则将ө2与栈顶的运算符ө1比较。如果栈顶的运算符ө1的优先级小于当前运算符ө2,则将当前运算符ө2进栈;如果栈顶的运算符ө1的优先级大于当前运算符 ө2,则将栈顶运算符 ө1出栈并将其作为后缀表达式输出。然后继续比较新的栈顶运算符ө1与当前运算符ө2的优先级,如果栈顶运算符ө1的优先级与当前运算符ө2相等,且ө1为‘(’,ө2为‘)’,则将ө1出栈,继续读入下一个字符。
(4)如果当前运算符 ө2的优先级与栈顶运算符 ө1相等,且 ө1和 ө2都为‘#’,将 ө1出栈,栈为空。则中缀表达式转换为后缀表达式,算法结束。
运算符优先关系表如表3.1所示。
表3.1 运算符优先关系表
中缀表达式a-(b+c*d)/e转换为后缀表达式的输出过程如表3.2所示。
表3.2 中缀表达式a-(b+c*d)/e转换为后缀表达式的过程
2.后缀表达式的计算
计算后缀表达式的值需要设置一个operator栈,用于存放操作数和中间运算结果。依次读入后缀表达式中的每个字符,如果是操作数,则将操作数进入operand栈;如果是运算符,则将操作数出栈两次,然后对操作数进行当前操作符的运算,直到整个表达式处理完毕。
后缀表达式的求值算法如下(假设栈顶运算符为ө1,当前扫描的运算符为ө2):
(1)初始化operand栈。
(2)如果当前读入的字符是操作数,则将该操作数进入operand栈。
(3)如果当前字符是运算符 ө,则将operand栈退栈两次,分别得到操作数x和y,对x和y进行ө运算,即yөx,得到中间结果z,将z进入operand栈。
(4)重复执行步骤(2)和(3),直到operand栈空为止。
3.表达式的运算举例
【例3.2】 利用栈将中缀表达式(5*(12-3)+4)/2转换为后缀表达式,并计算后缀表达式的值。
【分析】设置两个字符数组str和exp,str用来存放中缀表达式的字符串,exp用来存放后缀表达式的字符串。将中缀表达式转换为后缀表达式的方法是:依次扫描中缀表达式,如果遇到数字则将其存入数组exp中。如果遇到运算符,则将栈顶运算符与当前运算符比较,如果当前运算符的优先级大于栈顶运算符的优先级,则将当前运算符进栈;如果栈顶运算符的优先级大于当前运算符的优先级,则将栈顶运算符出栈,并保存到数组exp中。
为了处理方便,在遇到数字字符时,需要在其后补一个空格,作为分隔符。在计算后缀表达式的值时,需要对两位数以上的字符进行处理,将处理后的数字然后入栈。
中缀表达式转换为后缀表达式的算法如下。
计算后缀表达式的值的算法如下:
测试程序如下:
图3.9 程序运行结果
程序运行结果如图3.9所示。