天天看點

中綴表達式轉換為字尾表達式求值算法

轉載自:http://www.cnblogs.com/wanghetao/archive/2012/04/23/2466580.html

逆波蘭表達式

表達式一般由操作數(Operand)、運算符(Operator)組成,例如算術表達式中,通常把運算符放在兩個操作數的中間,

這稱為中綴表達式(Infix Expression),如A+B。

波蘭數學家Jan Lukasiewicz提出了另一種數學表示法,它有兩種表示形式:

把運算符寫在操作數之前,稱為波蘭表達式(Polish Expression)或字首表達式(Prefix Expression),如+AB;

把運算符寫在操作數之後,稱為逆波蘭表達式(Reverse Polish Expression)或字尾表達式(Suffix Expression),如AB+;

其中,逆波蘭表達式在編譯技術中有着普遍的應用。

算法:

一、 将中綴表達式轉換成字尾表達式算法:

1、從左至右掃描一中綴表達式。

2、若讀取的是操作數,則判斷該操作數的類型,并将該操作數存入操作數堆棧

3、若讀取的是運算符

  (1) 該運算符為左括号"(",則直接存入運算符堆棧。

  (2) 該運算符為右括号")",則輸出運算符堆棧中的運算符到操作數堆棧,直到遇到左括号為止。

  (3) 該運算符為非括号運算符:

      (a) 若運算符堆棧棧頂的運算符為括号,則直接存入運算符堆棧。

      (b) 若比運算符堆棧棧頂的運算符優先級高或相等,則直接存入運算符堆棧。

      (c) 若比運算符堆棧棧頂的運算符優先級低,則輸出棧頂運算符到操作數堆棧,并将目前運算符壓入運算符堆棧。

4、當表達式讀取完成後運算符堆棧中尚有運算符時,則依序取出運算符到操作數堆棧,直到運算符堆棧為空。

二、逆波蘭表達式求值算法:

1、循環掃描文法單元的項目。

2、如果掃描的項目是操作數,則将其壓入操作數堆棧,并掃描下一個項目。

3、如果掃描的項目是一個二進制運算符,則對棧的頂上兩個操作數執行該運算。

4、如果掃描的項目是一個一進制運算符,則對棧的最頂上操作數執行該運算。

5、将運算結果重新壓入堆棧。

6、重複步驟2-5,堆棧中即為結果值。

c++代碼示例

  1. *    這裡主要是逆波蘭式的實作,使用兩個stack 這裡用字元串來模拟一個stack,第一步,将中綴表達式轉變為字尾表達式 
  2. *    第二步,然後再使用一個stack,計算字尾表達式的結果,這一步很容易出錯,考慮到浮點數的問題。 
  3. */  
  4. #include <iostream>  
  5. #include <string>  
  6. #include <stack>  
  7. #include <iomanip>  
  8. using namespace std;  
  9. int cmp(char ch)     // 運算符優先級   
  10. {  
  11.     switch(ch)  
  12.     {  
  13.         case '+':  
  14.         case '-': return 1;  
  15.         case '*':  
  16.         case '/': return 2;  
  17.         default : return 0;  
  18.     }  
  19. }  
  20. void change(string &s1, string &s2)       // 中綴表達式轉變字尾表達式   
  21.     stack <char > s;  
  22.     s.push('#');  
  23.     int i = 0;  
  24.     while(i < s1.length()-1)  
  25.         if(s1[i] == '(')  
  26.         {  
  27.             s.push(s1[i++]);  
  28.         }  
  29.         else if(s1[i] == ')')  
  30.             while(s.top() != '(')  
  31.             {  
  32.                 s2 += s.top();  
  33.                 s2 += ' ';  
  34.                 s.pop();  
  35.             }  
  36.             s.pop();  
  37.             i++;  
  38.         else if(s1[i] == '+'||s1[i] == '-'||s1[i] == '*'||s1[i] == '/')  
  39.             while(cmp(s.top()) >= cmp(s1[i]))  
  40.             s.push(s1[i]);  
  41.         else  
  42.             while('0' <= s1[i]&&s1[i] <= '9'||s1[i] == '.')  
  43.                 s2 += s1[i++];  
  44.             s2 += ' ';  
  45.     while(s.top() != '#')  
  46.         s2 += s.top();  
  47.         s2 += ' ';  
  48.         s.pop();  
  49. double value(string s2)         // 計算字尾表達式,得到其結果。   
  50.     stack < double> s;  
  51.     double x,y;  
  52.     while(i < s2.length())  
  53.         if(s2[i] == ' ')  
  54.             continue;  
  55.         switch(s2[i])  
  56.             case '+': x = s.top(); s.pop(); x += s.top(); s.pop(); i++; break;  
  57.             case '-': x = s.top(); s.pop(); x =s.top()-x; s.pop(); i++; break;  
  58.             case '*': x = s.top(); s.pop(); x *= s.top(); s.pop(); i++; break;  
  59.             case '/': x = s.top(); s.pop(); x = s.top()/x; s.pop(); i++; break;  
  60.             default :  
  61.                 x = 0;  
  62.                 while('0' <= s2[i]&&s2[i] <= '9')  
  63.                 {  
  64.                     x = x*10+s2[i] - '0';  
  65.                     i++;  
  66.                 }  
  67.                 if(s2[i] == '.')  
  68.                     double k = 10.0;  
  69.                     y = 0;  
  70.                     while('0' <= s2[i]&&s2[i] <= '9')  
  71.                     {  
  72.                         y += ((s2[i]-'0')/k);  
  73.                         i++;  
  74.                         k *= 10;  
  75.                     }  
  76.                     x += y;  
  77.         s.push(x);  
  78.     return s.top();  
  79. int main(int argc, char const *argv[])  
  80.     int n;  
  81.     string s1,s2;  
  82.     cin>>n;  
  83.     while(n--)  
  84.         cin>>s1;  
  85.         s2 = "";  
  86.         change(s1,s2);  
  87.         cout<<fixed<<setprecision(2)<<value(s2)<<endl;  
  88.     return 0;  
  89. }