計算中綴表示式(實數,四則運算與括號)(雙棧)
阿新 • • 發佈:2019-02-05
之前寫過這方面的演算法,用的思想是先將中綴表示式轉化為字尾表示式,再計算。本文采用直接計算中綴表示式的方法,用兩個棧分別儲存,運算子和數值。另外在處理括號問題時,拋開之前增大優先順序的繁瑣方法,直接把括號當做一條新的式子,計算後返回一個值到原式,這也算是遞迴思想。最後,此次把資料域擴充到實數域。
瑕疵:程式碼沒有考慮除以0和一些不符合的情況,即輸入的式子都是符合運演算法則的。因為只是想體現演算法的核心,沒有必要搞得太繁瑣,需要的時候再加就是了。
#include<iostream> #include<stack> #include<string> using namespace std; const int power[6]={2,1,0,1,0,2};//四則運算的優先順序,分別對應*,+, ,-, ,/ double tqn(char s[],int &i)//提取數字 { double result=0; int j; while(s[i]!='.'&&s[i]!='+'&&s[i]!='-'&&s[i]!='*'&&s[i]!='/'&&s[i]!='('&&s[i]!=')'&&s[i]!='\0')//整數部分 { result=result*10+s[i]-'0'; i++; } if(s[i]=='.')//小數部分 { i++; for(j=10;s[i]!='+'&&s[i]!='-'&&s[i]!='*'&&s[i]!='/'&&s[i]!='('&&s[i]!=')'&&s[i]!='\0';j=j*10,i++) { result+=(double(s[i]-'0'))/j; } } i--;//考慮到原來的函式存在i自增,所以這裡要退一位 return result; } void calcular(stack<double> &num,stack<char> &op)//計算當前能計算的式子,就是暫時符合運演算法則的部分 { double a,b; while(!op.empty())//直到當前沒有運算子剩餘,即只剩下一個結果值 { b=num.top(); num.pop(); a=num.top(); num.pop(); switch(op.top()) { case '+':num.push(a+b);break; case '-':num.push(a-b);break; case '*':num.push(a*b);break; case '/':num.push(a/b);break; } op.pop(); } } double play(char s[],int &i,char flag)//操作式子 ,flag是式子結束標識 { double result=0; stack<double> num; stack<char> op; int j; for(;s[i]!=flag;i++) { if(s[i]>='0'&&s[i]<='9')//遇到數字即提取 num.push(tqn(s,i)); else { if(s[i]=='(')//遇到括號即當成一個新的式子 { i++; num.push(play(s,i,')'));//括號的結束標識為')' } else { if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/')//遇到運算子 { if(op.empty())//空即入 op.push(s[i]); else { if(power[s[i]-42]<power[op.top()-42])//當前運算子優先順序小於上一個運算子的優先順序,即前面的可以計算了 { calcular(num,op); } op.push(s[i]);//插入當前運算子 } } } } } calcular(num,op);//計算剩下的 result=num.top(); num.pop(); return result; } int main() { int i;//列舉下標 double result; char s[1000]; stack<char> op;//運算子棧 stack<double> num;//數值棧 while(cin.getline(s,1000)) { i=0; result=play(s,i,'\0'); cout<<result<<endl; } return 0; }