C++實現任意運算式求值(棧)__C++

來源:互聯網
上載者:User

今天花了大概四個小時時間,用棧(stack)實現了“任意運算式的值計算”的問題。

 

C++ 比 C 好的一點就是,C++ 的STL定義了大量的資料類型和演算法,相比於 C 更加視覺化。

 

實現這個的基本思路很簡單:分成兩部分完成。兩個主要函數:

    string shorten(string m) 把 string m 由中綴式變為右綴式,double calculate(string s) 計算右綴式的運算式值。

數字寫入右綴式m很簡單,不過別忘了用個符號把數字分開。我選擇的是$。

比較難的地方是shorten函數,分析怎樣把 string m 變為右綴式。可能的計算有這麼幾種:+,-,*,/,()。於是我通過列表的方式來分析:

    +|- *|/ (   空

+|- m+=c    m+=c    push    push

*|/ push    m+=c    push    push

(   push    push    push    push

)   m+=c    m+=c    m+=c    XXXX    (XXXX表示不可能發生的情況)

豎行是操作符,橫行是對應每一個豎行可能遇到的情況,“空”代表棧為空白。push表示入棧,m+=c表示元素出棧,寫入運算式(右綴式)m。

其實列表的原則挺簡單的:

    1. 把“(”看做開闢一次新的棧(從“(”開始算,忽視之前的元素,直到“)”被取消);

    2. 元素a遇到相同或更高優先順序的,棧頂元素c出棧,給右綴運算式m;再次對比;直到遇到更高優先順序的,元素a入棧;

    3. “)”出現的時候,之前所有元素依次出棧,寫入m,直到“(”;

    4. 在數字都加入右綴運算式之後,棧中所有元素依次出棧,寫入m,直到棧為空白。

關鍵就是 2、3條,我花了好久才總結出來的規律。順便說下,列表法真的是很好的分析問題的方式,不重不漏還簡練。

 

然後進行右綴運算式的計算,這個比較簡單:數字依次入棧,遇到操作符後對棧頂的兩個元素進行順序操作(倒數第二個 +-*/ 倒數第一個),然後把這兩個元素換成新的結果。如此迴圈即可。

 

原題目要求用int即可,但用int必然會造成除法的不精確。所以考慮用double類型,並且在讀取的時候可以支援小數點。記得是有直接轉化的函數,但忘了,所以自己寫啦,命名為 str2double(string s)。有個dec變數決定計算整數部分還是小數部分,詳細可參見函數。

 

這次實踐這個程式還有個小收穫,是在我無數次的debug之中:可以在某些關鍵步驟(比較容易發現bug的地方)加上輸出語句,這樣可以判斷程式是否運行過了這些關鍵地方。

還有,順便提一下,“模組化”的思想真的很重要,不然在進行一些小改動時,那種“牽一髮而動全身”的感覺很焦慮、很淩亂。

#include <iostream> #include <string> #include <stack> #include <fstream> using namespace std; bool isone(char c){ return (c=='+' || c=='-'); } bool istwo(char c){ return (c=='*' || c=='/'); } string shorten(string m){ stack<char> s; string sur; int i; char w; sur; for(i=0;i<m.size();i++){ if(isdigit(m[i]) || m[i]=='.'){ while(isdigit(m[i]) || m[i]=='.') sur += m[i++]; i--; sur += '$'; } else if(isone(m[i])){ while(s.size() && (isone(s.top()) || istwo(s.top()))){ sur+=s.top(); s.pop(); } s.push(m[i]); } else if(m[i]==')'){ while(s.top()!='('){ sur+=s.top(); s.pop(); } s.pop(); } else if(istwo(m[i])){ while(s.size() && istwo(s.top())){ sur+=s.top(); s.pop(); } s.push(m[i]); } else s.push(m[i]); } while(s.size()){ sur+=s.top(); s.pop(); } return sur; } double tentimes(int n){ double res=1; for(int i=0;i<n;i++){ res *= 10; } return res; } double str2double(string s){ double res=0; char c; int dec=0; for(int i=1;i<=s.size();i++){ c=s[i-1]; if(c=='.') dec=i; else if(!dec) res = res*10 + c-'0'; else res += (c-'0')/tentimes(i-dec); } return res; } double calculate(string s){ double res, t; stack<double> num; string temp; int i; for(i=0;i<s.size();i++){ temp=""; if(isdigit(s[i]) || s[i]=='.'){ while(isdigit(s[i]) || s[i]=='.') temp+=s[i++]; //如果最後一位是數字,這樣做會出錯 num.push(str2double(temp)); } else{ switch (s[i]){ case '+': t=num.top(); num.pop(); t+=num.top();num.pop();num.push(t);break; case '-': t=num.top(); num.pop(); t=num.top()-t;num.pop();num.push(t);break; case '*': t=num.top(); num.pop(); t*=num.top();num.pop();num.push(t);break; case '/': t=num.top(); num.pop(); t=num.top()/t;num.pop();num.push(t);break; default: cerr << "Fatal Error! Result would be wrong!" << endl; system("pause");break; } } } res=num.top(); return res; } int main(){ string mid, sur; cin >> mid; sur = shorten(mid); cout << "successfully executed! The right hand operator expression is: " << endl; cout << sur << endl; cout << "The result is: " <<calculate(sur) << endl; system("pause"); return 0; }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.