原文链接:http://blog.csdn.net/qshpeng/archive/2007/11/10/1877000.aspx
在程序设计过程中,可能碰到需要对字符串型数学表达式进行求值,通用且完美的方法是将字符串表达解析,生成表达树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等。
我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式。除此之外,还有前序表达式,后序表达式。如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了。
既然使用生成表达式树的方法直接执行通常的中序表达式有点困难,那就考虑一下其它的两个表达式吧。这里介绍如何用后序表达式来求值,这种方法早在以前就有人介绍了,因为其简单,易实现,故偶在这里重新阐述一下。
后缀表达式——将运算符放在两操作数的后面。后缀表达式也称逆波兰表达式 因其使表达式求值变得轻松,所以被普遍使用。
前缀和后缀表示法有三项公共特征:
1.操作数的顺序与等价的中缀表达式中操作数的顺序一致
2.不需要括号
3.操作符的优先级不相关
当然我们不可能自己特意去写一个后序表达式,这样很难受,因为我们早就习惯了中序表达式这种形式,因此我们需要将中序表达首先转化为后序表达式,去掉括号。中缀转后缀是栈应用的一个典型例子。其转换方法采用运算符优先法。转换过程需借助一个运算符栈和一个存放逆波兰表达式的数组。
转换方法如下:
1.将表达式开始符“#”压入运算符栈,作为栈底元素。
2.读入操作数,直接存入数组。
3.读入运算符,压入运算符栈。
若后进运算符优先级别高于当前栈顶元素时,则继续进栈;
若后进运算符优先级别低于或等于当前栈顶元素时,则将当前栈顶元素出栈,存入数组后进运算符入栈。
4.括号处理
遇到开括号"(",将括号进运算符栈;遇到闭括号")",则把最靠近的开括号,以及该开括号其遇到闭括号,后进栈的运算符依次出栈,存入数组(括号脱去)
5.遇到表达式结束符则把运算符栈内的所有运算符依次弹出,并存入数组。
后缀表达式的执行:
1.先读入两个操作数,遇到操作符,则将这两个操作数进行该操作符对应的计算。
2.保存计算结果,并将其作为下一个操作的第一个操作数。
3.读入下一个操作数,如果已到表达式结尾(即读到空),则算法结束,否则进行第4步
4.读入下一个操作符,进行对应的计算。转第2步。
上面的方法可以使用任意程序设计语言来实现。这里提供一个C#实现的类,该类利用了C#语言特有的一些性质,可以对任意的表达式求值,并且能够解析字符串形式的代码。