首先要知道如何求逆波蘭式(後綴表達式):php
表達式的表示形式有中綴、前綴和後綴3中形式。中綴表達式按操做符的優先級進行計算(後面代碼實現只包括+、-、*、\,小括號),即數學運算。 後綴表達式中只有操做數和操做符。操做符在兩個操做數以後。它的計算規則很是簡單,嚴格按照從左到右的次序依次執行每個操做。每遇到一個操做符,就將前面的兩個數執行相應的操做。
由後綴表達式計算中綴表達式原理:計算機處理後綴表達式求值問題是比較方便的,即將遇到的操做數暫存於一個操做數棧中,凡是遇到操做數,便從棧中pop出兩個操做數,並將結果存於操做數棧中,直到對後綴表達式中最後一個操做數處理完,最後壓入棧中的數就是後最表達式的計算結果。 ios
中綴表達式轉換爲等價的後綴表達式
中綴表達式不方便與計算機處理,一般要講中綴表達式轉換爲一個與之等價的後綴表達式。等價是指兩個表達式的計算順序和計算結果徹底相同。
中綴表達式:0.3/(5*2+1)# 的等價後綴表達式是:0.3 5 2 * 1 + /#
仔細觀察這兩個等價的表達式可知,操做數的出現次序是相同的,但運算符的出現次序是不一樣的。在後綴表達式中,運算符的出現次序是實際進行操做的次序;在中追表達式中,因爲受到操做符的優先級和括號的影響,操做符出現次序與實際進行操做的次序極可能是不同的。 git
算法描述:
將中綴表達式轉換爲等價的後綴表達式的過程要使用一個棧放「(」,具體能夠按照下面的方式進行。
(1)從左到右依次掃描中綴表達式的每個字符,若是是數字字符和圓點「.」則直接將它們寫入後綴表達式中。
(2)若是遇到的是開括號「(」,則將它們壓入一個操做符棧(不須要與棧頂操做符相比較),它代表一個新的計算層次的開始,在遇到和它匹配的閉括號「)」時,將棧中的元素彈出來並放入後綴表達式中,直到棧頂元素爲「(」時,將棧頂元素「(」彈出(不須要加入後綴表達式),代表這一層括號內的操做處理完畢。
(3)若是遇到的是操做符,則將該操做符和操做符棧頂元素比較:
一、當所遇到的操做符的優先級小於或等於棧頂元素的優先級時,則取 出棧頂元素放入後綴表達式,並彈出該棧頂元素,反覆執行直到當前操做符的優先級大於棧頂元素的優先級小於;算法
二、當所遇到的操做符的優先級大於棧頂元素的優先級的時則將它壓入棧中。 post
(4)重複上述步驟直到遇到中綴表達式的結束符標記「#」,彈出棧中的全部元素並放入後綴表達式中,轉換結束.net
——copy from 飄過的小牛blog
獲得後綴表達式,就不難計算表達式的值,若是是數字壓入棧,當遇到運算符,彈出兩個(雙目)數字計算後再壓棧,答案就是棧剩下的最後一個數字ci
代碼:get
/* 表達式求值,逆波蘭式(後綴表達式)算法 輸入(能夠有空格,支持小數,實現'+-/*%'): ((1+2)*5+1)/4= 注意:取模必定是要整型,實現版本數字全是double,強制類型轉換可能倒置錯誤 轉換爲後綴表達式: 獲得:1 2 + 5 * 1 + 4 / = 計算後綴表達式:獲得:4.00 */ struct Exp { stack<char> op; stack<double> num; bool error; int prior(char ch) { //運算符的優先級 switch (ch) { case '+': case '-': return 1; case '*': case '%': case '/': return 2; default: return 0; } } bool is_digit(char ch) { return '0' <= ch && ch <= '9'; } string get_postfix(string s) { //中綴表達式轉變後綴表達式 while (!op.empty ()) op.pop (); op.push ('#'); string ret = ""; int len = s.length (), i = 0; while (i < len) { if (s[i] == ' ' || s[i] == '=') { i++; continue; } else if (s[i] == '(') { op.push (s[i++]); } else if (s[i] == ')') { while (op.top () != '(') { ret += op.top (); ret += ' '; op.pop (); } op.pop (); i++; } else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%') { while (prior (op.top ()) >= prior (s[i])) { ret += op.top (); ret += ' '; op.pop (); } op.push (s[i++]); } else { while (is_digit (s[i]) || s[i] == '.') { ret += s[i++]; } ret += ' '; } } while (op.top () != '#') { ret += op.top (); ret += ' '; op.pop (); } ret += '='; return ret; } double cal(double a, double b, char ch) { if (ch == '+') return a + b; if (ch == '-') return a - b; if (ch == '*') return a * b; if (ch == '%') return (int)((int)a % (int)b); if (ch == '/') { if (b != 0) return a / b; error = true; return 0; } } double solve(string str) { //計算後綴表達式 string s = get_postfix (str); while (!num.empty ()) num.pop (); error = false; int len = s.length (), i = 0; while (i < len) { if (s[i] == ' ' || s[i] == '=') {i++; continue;} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%') { double a = num.top (); num.pop (); double b = num.top (); num.pop (); num.push (cal (b, a, s[i])); i++; } else { double x = 0; while (is_digit (s[i])) { x = x * 10 + s[i] - '0'; i++; } if (s[i] == '.') { double k = 10.0, y = 0; i++; while (is_digit (s[i])) { y += ((s[i] - '0') / k); i++; k *= 10; } x += y; } num.push (x); } } return num.top (); } }E; int main(void) { ios::sync_with_stdio (false); //若是全用流的話,加這句話能跑快點 int T; cin >> T; string str; getline (cin, str); while (T--) { getline (cin, str); cout << E.get_postfix (str) << endl; cout << fixed << setprecision (6) << E.solve (str) << endl; } return 0; }
拿着這個模板就能夠解決:NYOJ_467_中綴式變後綴式,NYOJ_35_表達式求值,HDOJ_1237_簡單計算器,以及ZSTOJ_4189_邏輯運算 ('!'是單目運算符)數學