逆波兰式

2013-09-20 21:54:28

转自:http://blog.csdn.net/simplebelief/article/details/6347149

在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等。我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式。除此之外,还有前序表达式,后序表达式。如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了。

后缀表达式也称逆波兰表达式 因其使表达式求值变得轻松,所以被普遍使用。

 

逆波兰式:

       在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间(如:1+1),所以这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,称为逆波兰记法,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。示例如下:

中缀表示

逆波兰式

a+b

a,b,+

a+(b-c)

a,b,c,-,+

a+(b-c)*d

a,b,c,-,d,*,+

a+d*(b-c)

a,d,b,c,-,*,+

a=1+3

a=1,3 +

逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。

      

中缀表达式转换为逆波兰式:

将一个普通的中序表达式转换为逆波兰表达式的一般算法是:

1、首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

2、读入一个中缀表达式,为了方便起见,可在其最右端追加一个最低优先级运算符(如:#号)。(这样做的目的是,最后读入#号运算符时将运算符栈中所有运算符都输出)。

3、从左至右扫描该中缀表达式,如果当前字符是数字,则分析到该数字串的结束,并将该数字串直接输出。

4、如果不是数字,该字符则是运算符,此时需比较该运算符与运算符栈顶运算符的优先关系:

(1)、若该运算符优先级高于栈顶运算符优先级别(或栈为空),则直接将该运算符压入运算符栈中;

(2)、若该运算符优先级小于或等于此运算符栈顶的运算符,则弹出栈顶运算符并输出,重复比较、输出,直到栈为空或该运算符优先级高于栈顶运算符,然后将该运算符入栈。

5、重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,输出结果便是中缀表达式转化为逆波兰表示的简单算术表达式。

      

运算符优先级参考:

       优先级分为栈内优先级isp(In stack priority)和栈外优先级icp(In coming priority)。除了括号以外,其他运算符进栈后优先级都升1,这样可以体现在中缀表达式中相同优先级的操作符自左向右计算的要求,让位于栈顶的操作符先退栈并输出。各运算符及符号优先级:

操作符

#

^

*,/,%

+,-

(

)

isp

0

7

5

3

1

8

icp

0

6

4

2

8

1

 

后缀表达式建二叉树:

 

  1. //后缀表达式建树 样例:1 2 3 * + 4 -  
  2.     void ExpTree::PostOrderCreate(string str)  
  3. {  
  4.     Stack<TNode*> nodeStack;  
  5.     for (int i = 0; i < str.length(); i++)  
  6.     {  
  7.         if (str[i] == ' ') // 分隔符  
  8.             continue;  
  9.         switch (str[i])  
  10.         {  
  11.         case '+': case '-': case '*': case '/':  
  12.             nodeStack.push(new TNode(str[i], nodeStack.pop(), nodeStack.pop()));  
  13.             break;  
  14.         default:  
  15.             nodeStack.push(new TNode(str[i] - '0'));  
  16.             break;  
  17.         }  
  18.     }  
  19.    
  20.     m_pRoot = nodeStack.pop();  
  21. }  

 

 

 

计算二叉树表达式值:

 

  1. //计算  
  2. int ExpTree::Cacul(int a, char op, int b)  
  3. {  
  4.     switch (op)  
  5.     {  
  6.         case '+': return a + b;  
  7.         case '-': return a - b;  
  8.         case '*': return a * b;  
  9.         case '/': return a / b;     
  10.     }  
  11. }  
  12. //求值函数  
  13. int ExpTree::Caculate(TNode* cur)  
  14. {  
  15.     if (cur->left == NULL && cur->right == NULL)  
  16.         return cur->opnd;  
  17.     else  
  18.         return Cacul(val(cur->left), cur->optr, val(cur->right));  
  19. }  

 

 

 

 

源代码下载:http://download.csdn.net/source/3219514

posted @ 2013-09-20 21:55  永不止步,永无止境  阅读(440)  评论(0)    收藏  举报