前綴表達式(波蘭表達式)、中綴表達式、后綴表達式(逆波蘭表達式)
介紹
三種表達式都是四則運算的表達方式,用以四則運算表達式求值,即數學表達式的求解。
前綴表達式
-
前綴表達式是一種沒有括號的算術表達式,與中綴表達式不同的是,其將運算符寫在前面,操作數寫在后面。為紀念其發明者波蘭數學家Jan Lukasiewicz,前綴表達式也稱為“波蘭式”。例如,- 1 + 2 3,它等價於1-(2+3)。
中綴表達式
-
中綴表達式就是一般的算數表達式,操作符以中綴形式出現在操作數之間。
后綴表達式
-
后綴表達式指的是不包含括號,運算符放在兩個運算對象的后面,所有的計算按運算符出現的順序,嚴格從左向右進行(不再考慮運算符的優先規則)。
中綴表達式轉前綴表達式
例如:對於中綴表達式(3+4)×5-6,其前綴表達式為- × + 3 4 5 6。前后綴表達式與中綴之間的轉換關系,不在此贅述,在Seraphjin的博客中,通過二叉樹的方式,很好地解釋了這一內容。
除了該博客中所說的二叉樹法,還可以通過棧方法,來實現二者的轉換,具體步驟如下:
- 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
- 從右至左掃描中綴表達式;
- 遇到操作數時,將其壓入S2;
- 遇到運算符時,比較其與S1棧頂運算符的優先級:
- 如果S1為空,或棧頂運算符為右括號“)”,則直接將此運算符入棧;
- 否則,若優先級比棧頂運算符的較高或相等,也將運算符壓入S1;
- 否則,將S1棧頂的運算符彈出並壓入到S2中,再與S1中新的棧頂運算符相比較;
- 遇到括號時:
- 如果是右括號“)”,則直接壓入S1;
- 如果是左括號“(”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到右括號為止,此時將這一對括號丟棄;
- 重復上述步驟,直到表達式的最左邊;
- 將S1中剩余的運算符依次彈出並壓入S2;
- 依次彈出S2中的元素並輸出,結果即為中綴表達式對應的前綴表達式。
前綴表達式的計算機求解
利用計算器對前綴表達式求解其算數值時,采用從左到右掃描的方法,遇到操作數,則將其入棧,遇到操作符,則從棧中彈出兩個操作數,由於前綴操作符位於數字之前,因此,第二個彈出的操作數為被操作數。然后對兩個操作數根據操作符做相應的操作。
- 從右至左掃描,將6、5、4、3壓入堆棧
- 遇到+運算符,因此彈出3和4(3為棧頂元素,4為次頂元素,注意與后綴表達式做比較),計算出3+4的值,得7,再將7入棧
- 接下來是×運算符,因此彈出7和5,計算出7×5=35,將35入棧
- 最后是-運算符,計算出35-6的值,即29,由此得出最終結果
中綴表達式轉后綴表達式
表達式的轉換,有二叉樹法和棧方法,二叉樹法不在此追述,詳情見上文鏈接。
棧方法將中綴表達式轉后綴表達式的方法如下所示:
- 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
- 從左至右掃描中綴表達式;
- 遇到操作數時,將其壓入S2;
- 遇到運算符時,比較其與S1棧頂運算符的優先級:
- 如果S1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
- 否則,若優先級比棧頂運算符的高,也將運算符壓入S1(注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
- 否則,將S1棧頂的運算符彈出並壓入到S2中,再與S1中新的棧頂運算符相比較;
- 遇到括號時:
- 如果是左括號“(”,則直接壓入S1;
- 如果是右括號“)”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到左括號為止,此時將這一對括號丟棄;
- 重復上述步驟,直到表達式的最右邊;
- 將S1中剩余的運算符依次彈出並壓入S2;
- 依次彈出S2中的元素並輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不 用逆序)。
后綴表達式在算數邏輯運算中的作用,以及簡單計算器的C++實現
由上述內容可知,利用前綴或者后綴表達式,可以很好的利用計算器,解決日常中綴表達式的求解,在此基礎上,給出,無括號情況下,簡單計算器的實現。
.h文件代碼

1 #ifndef _C_H_ 2 #define _C_H_ 3 #include<iostream> 4 #include<string> 5 #include<algorithm> 6 #include<stdio.h> 7 #include<map> 8 #include<queue> 9 #include<stack> 10 #include<cstdio> 11 #endif
.cpp
文件代碼

1 #include "C.h" 2 3 using namespace std; 4 5 struct node{ 6 double num; //操作符 7 char op; //操作數 8 bool flag; //數符判定 9 10 }; 11 12 string str; //輸入字符串 13 stack<node> s; //操作符棧 14 queue<node> q; //操作數隊列 15 map<char, int>op; //操作符優先級 16 17 void Change(); //中綴表達式轉后綴表達式 18 double Cal(); //計算表達式的值 19 20 int main(){ 21 op['*'] = op['/'] = 2; 22 op['+'] = op['-'] = 1; 23 while(getline(cin, str), str!="0"){ 24 for(string::iterator it = str.end();it!=str.begin();it--){ 25 if(*it == ' '){ 26 str.erase(it); //擦除表達式中的空格 27 } 28 } 29 while(!s.empty()){ 30 s.pop(); //初始化棧 31 } 32 Change(); //中綴表達式轉換為后綴表達式 33 double rs = Cal(); 34 printf("%.2f\n", rs); 35 } 36 37 return 0; 38 } 39 40 //中綴表達式轉后綴表達式 41 void Change(){ 42 node temp; 43 for(unsigned int i=0;i<str.length();){ 44 if(str[i]>='0'&&str[i]<='9'){ //為操作數 45 temp.flag = true; 46 temp.num = str[i++] - '0'; //記錄該操作數的最高位 47 while(i<str.length() && str[i]>='0' && str[i]<='9'){//記錄該操作數的后續幾位 48 temp.num = temp.num * 10 + (str[i] - '0'); //更新操作數 49 i++; 50 } 51 q.push(temp); 52 } 53 else{//為操作符 54 temp.flag = false; 55 while(!s.empty()&&op[str[i]]<=op[s.top().op]){ 56 q.push(s.top()); 57 s.pop(); 58 } 59 temp.op = str[i]; 60 s.push(temp); 61 i++; 62 } 63 } 64 while(!s.empty()){//操作符棧非空,則直接入后綴表達式隊列 65 q.push(s.top()); 66 s.pop(); 67 } 68 } 69 70 double Cal(){ 71 double temp1, temp2; 72 node cur, temp; 73 while(!q.empty()){ 74 cur = q.front(); 75 q.pop(); 76 if(cur.flag){ 77 s.push(cur); 78 } 79 else{ 80 temp.flag = true; //暫存計算數據 81 temp2 = s.top().num; //取第2操作數 82 s.pop(); 83 temp1 = s.top().num; //取第1操作數 84 s.pop(); 85 if(cur.op=='+'){ 86 temp.num = temp1 + temp2; 87 } 88 else if(cur.op=='-'){ 89 temp.num = temp1 - temp2; //后綴表達式,操作符在原表達式中位於操作數2和操作數1之間 90 } 91 else if(cur.op=='*'){ 92 temp.num = temp1 * temp2; 93 } 94 else{ 95 temp.num = temp1 / temp2; 96 } 97 s.push(temp); 98 } 99 } 100 return s.top().num; 101 }
有括號輸入表達式下,計算器的實現:

1 #include "C.h" 2 3 using namespace std; 4 5 struct node{ 6 double num; //操作數 7 char op; //操作符 8 bool flag; //數符定界,若真則為操作數,反之為操作符 9 }; 10 11 string str; //輸入字符串 12 map<char, int> m; //操作符優先級 13 queue<node> q; //操作數隊列 14 stack<node> s; //操作符棧 15 16 17 void Change(){ 18 /* 19 *中綴表達式轉后綴表達式 20 */ 21 node temp; 22 for(unsigned int i=0;i<str.length();){ 23 if(str[i]>='0'&&str[i]<='9'){//字符為操作數 24 temp.flag = true; 25 temp.num = str[i++] - '0'; //記錄該操作數 26 while(i<str.length()&&str[i]>='0'&&str[i]<='9'){ //記錄該操作數的后續幾位 27 temp.num = temp.num * 10 + (str[i] - '0'); 28 i++; 29 } 30 q.push(temp); 31 } 32 else if(str[i]=='+'||str[i]=='-'||str[i]=='/'||str[i]=='*'||str[i]=='('){ 33 temp.flag = false; 34 if(!s.empty()&&s.top().op=='('){//判斷操作符棧棧頂是否為左括號 35 temp.op = str[i]; 36 s.push(temp); 37 } 38 else{ 39 while(!s.empty()&&m[str[i]]<=m[s.top().op]){ 40 q.push(s.top()); 41 s.pop(); 42 } 43 temp.op = str[i]; 44 s.push(temp); 45 } 46 i++; 47 } 48 else{ 49 while(!s.empty()&&s.top().op!='('){ 50 q.push(s.top()); 51 s.pop(); 52 } 53 s.pop(); 54 i++; 55 } 56 } 57 while(!s.empty()){ 58 q.push(s.top()); 59 s.pop(); 60 } 61 } 62 63 double Cal(){ 64 node cur, temp; 65 double temp1, temp2; 66 while(!q.empty()){ 67 cur = q.front(); 68 q.pop(); 69 if(cur.flag){ 70 s.push(cur); 71 } 72 else{ 73 temp2 = s.top().num; 74 s.pop(); 75 temp1 = s.top().num; 76 s.pop(); 77 if(cur.op=='*'){ 78 temp.num = temp1 * temp2; 79 } 80 else if(cur.op=='+'){ 81 temp.num = temp1 + temp2; 82 } 83 else if(cur.op=='-'){ 84 temp.num = temp1 - temp2; 85 } 86 else{ 87 temp.num = temp1 / temp2; 88 } 89 s.push(temp); 90 } 91 } 92 return s.top().num; 93 } 94 95 int main(){ 96 m['('] = m[')'] = 3; 97 m['*'] = m['/'] = 2; 98 m['+'] = m['-'] = 1; 99 100 while(getline(cin, str), str!="0"){ 101 for(string::iterator it=str.end();it!=str.begin();it--){ 102 if(*it==' '){ 103 str.erase(it); 104 } 105 } 106 cout<<str<<endl; 107 while(!s.empty()){ 108 s.pop(); 109 } 110 Change(); 111 printf("%.2f\n", Cal()); 112 } 113 114 return 0; 115 }