A+B*(C-D)-E*F的语法树如下:
1.中缀表达式
1.1定义
我们最熟悉的一种表达式A+B*(C-D)-E*F等是中缀表示法。中缀表达式是由相应的语法树中序遍历得到的。
中缀表达式先算括号里的,然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不方便,因为没有一种简单的数据结构可以比较方便的从一个表达式中间抽出一部分进行计算,计算完成后再放进去,然后继续后面的计算(链表也许可以,但是,代价也是不菲)。
2.前缀表达式
2.1定义
前缀表达式又叫做波兰式。同样的道理,表达式的前缀表达式是由相应语法树的前序遍历得到的。
如上图的前缀表达式为:
- -+A * B - C D * E F
2.2求值
由前缀表达式求出结果有下面两种思路:
思路1
1.从左至右扫描表达式,如果一个操作符后面跟着两个操作数时,则计算,然后将结果作为操作数替换(这个操作符和两个操作数)
2.重复第1步,直至所有操作符处理完毕。如-+AB-CDEF,扫描到-CD时,会计算C-D=C’,表达式变成:-+ABC’EF,继续扫描到BC’,计算BC’=B’表达式变成:-+AB’*EF,继续+AB’,依此类推。
思路2
要多遍扫描表达式,并且需要将3个字符替换成1个,比较繁锁,我们可以用一个栈S2来实现计算,扫描从右往左进行。如果扫描到操作数,则压进S2,如果扫描到操作符,则从S2弹出两个操作数进行相应的操作,并将结果压进S2(S2的个数出2个进1个),当扫描结束后,S2的栈顶就是表达式结果。
2.3中缀表达式转换为前缀表达式
中缀表达式转换成前缀表达式和中缀表达式转换成后缀表达式十分类似,只需要将扫描方向由前往后变成由后往前,将"(“改为”)",")“改为”("。
3.后缀表达式(逆波兰式)
3.1 定义
后缀表达式又叫做逆波兰式。它是由相应语法树后序遍历得到的。如上图的后缀表达式为:
- A B C D - * + E F * -
3.2 求值
根据逆波兰式计算结果,需要借助栈(Stack)这种数据结构来计算原式的值。栈(Stack)是限定仅在表尾进行插入或删除操作的线性表,遵循后进先出(Last In First Out,LIFO)的原则。
具体步骤如下:
- 从左到右扫描表达式,如果当前字符为数字,则入栈。
- 如果当前字符为运算符,则将栈顶两个元素出栈,作相应运算,结果再入栈。
- 最后当表达式扫描完后,栈里的就是计算结果了。
我们以1 2 3 4 + * + 5 -为例:
最终的计算结果为:10。
3.3 中缀表达式转换为后缀表达式
中缀表达法转换成逆波兰式,需要借助栈这种数据结构,具体步骤如下:
- 从左到右扫描中缀表达式,如果当前字符为数字就直接输出。
- 如果当前字符为运算符,则判断其与栈顶运算符的优先级。
- 如果是右括号或者优先级低于栈顶运算符,则栈内运算符依次出栈并输出,直到遇到左括号,然后当前运算符入栈。
- 最后当中缀表达式扫描完后,输出的就是逆波兰式了。
伪代码如下:
PROCESS BEGIN:
从左往右扫描中缀表达式串s,对于每一个操作数或操作符,执行以下操作;
IF (扫描到的s[i]是操作数DATA)
将s[i]添加到输出串中;
IF (扫描到的s[i]是开括号'(')
将s[i]压栈;
WHILE (扫描到的s[i]是操作符OP)
IF (栈为空 或 栈顶为'(' 或 扫描到的操作符优先级比栈顶操作符高)
将s[i]压栈;
BREAK;
ELSE
出栈至输出串中
IF (扫描到的s[i]是闭括号')')
栈中运算符逐个出栈并输出,直到遇到开括号'(';
开括号'('出栈并丢弃;
返回第1步
WHILE (扫描结束而栈中还有操作符)
操作符出栈并加到输出串中
PROCESS END
我们以1 + 2 * ( 3 + 4 ) - 5为例:
最终的逆波兰式为:1 2 3 4 + * + 5 -。