參考1:https://www.cnblogs.com/hantalk/p/8734511.html
參考2:https://blog.csdn.net/Coder_Dacyuan/article/details/79941743
題目描述
模擬計算機處理算術表達式過程。從鍵盤上輸入算術表達式串(只含+、-、×、÷運算符,允許含括號),輸出算術表達式的值。設輸入的表達式串是合法的,且只包含整數。
輸入
一行,中綴表達式,長度不超過255,以“@”結束。
輸出
中綴表達式的值。
樣例輸入
4+5-9+10*2@
樣例輸出
20
分析
表達式
中綴表達式(常用表達式)、前綴表達式(波蘭式)、後綴表達式(逆波蘭式)
中綴表達式:操作符是以中綴形式處於操作數的中間,中綴表達式是人們常用的算術表示方法。
前綴表達式:也叫波蘭式,不包含括號,運算符放在兩個運算對象的前面。
後綴表達式:也叫逆波蘭式,不包含括號,運算符放在兩個運算對象的後面,所有的計算按運算符出現的順序,嚴格從左向右進行。
比如:a+b
中綴:a+b 前綴:+ab 後綴:ab+
再比如:(a+b)*(c-d)
中綴:(a+b)*(c-b) 前綴:*+ab-cd 後綴:ab+cb-*
中綴轉前綴/後綴 手工算法
1、給每個表達式加上括號
2、將移動每個二元運算符,將其放在與其相應括號的左/右括號處
3、刪除所有括號
如: 中綴表達式爲:a/b-c+d*e-a*c
執行第一步:((((a/b)-c)+(d*e))-(a*c))
執行第二步:
前綴:(-(+(-(/ab)c)(*de))(*ac)) //左括號處
後綴:((((ab/)c-)(de*)+)(ac*)-) //右括號處
執行第三步:
前綴:-+-/abc*de*ac
後綴:ab/c-de*+ac*
中綴轉前綴 計算機算法
1、初始化兩個棧:運算符棧s1,儲存中間結果的棧s2
2、從右至左掃描中綴表達式
3、遇到操作數時,將其壓入s2
4、遇到運算符時,比較其與s1棧頂運算符的優先級
1若優先級比棧頂運算符的較高或相等,或s1爲空,或棧頂運算符爲右括號“)”,則直接將此運算符入棧
2否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到(4-1)與s1中新的棧頂運算符相比較
5遇到括號時
如果是右括號“)”,則直接壓入s1
如果是左括號“(”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到右括號爲止,此時將這一對括號丟棄
6、重複步驟2至5,直到表達式的最左邊
7、 將s1中剩餘的運算符依次彈出並壓入s2
8、依次彈出s2中的元素並輸出,結果即爲中綴表達式對應的前綴表達式
中綴轉後綴 計算機算法
1、初始化一個棧:運算符棧s;
2、從左至右掃描中綴表達式;
3、遇到操作數時,輸出;
4、遇到運算符時,比較其與s棧頂運算符的優先級:
1若優先級比s棧頂運算符的高,或者s爲空,或者左括號“(”,則直接將此運算符入棧;
2否則,將s棧頂的運算符輸出,再次轉到(4-1)與s中新的棧頂運算符相比較;
5、遇到括號時:
如果是左括號“(”,則直接壓入s;
如果是右括號“)”,則依次彈出s棧頂的運算符,輸出,直到遇到左括號爲止,此時將這一對括號丟棄;
6、重複步驟2至5,直到表達式的最右邊;
7、將s中剩餘的運算符依次彈出並輸出;
以上輸出即爲後綴表達式。
前綴表達式求值
從右至左掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(棧頂元素 運算符 次頂元素),並將結果入棧;重複上述過程直到表達式最左端,最後運算得出的值即爲表達式的結果
後綴表達式求值
從左至右掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 運算符 棧頂元素),並將結果入棧;重複上述過程直到表達式最右端,最後運算得出的值即爲表達式的結果。
#include<iostream>
#include<string>
#include<stack>
using namespace std;
string s;
stack<int> num;
stack<char> sym;
char lev[128];
void calculate(){ //計算
int x=num.top(); num.pop();
int y=num.top(); num.pop();
switch (sym.top()){
case '+': y+=x; break;
case '-': y-=x; break;
case '*': y*=x; break;
case '/': y/=x; break;
}
num.push(y); //運算後值入數字棧
sym.pop(); //運算符棧出棧
}
int main(){
cin>>s;
lev['+']=lev['-']=1; lev['*']=lev['/']=2; //運算符優先級
for (int i=0,len=s.size()-1; i<len; ){
if (s[i]=='(') sym.push(s[i]),i++; //左括號直接入棧
else if (s[i]==')'){ //右括號
while (sym.top()!='(') calculate(); //運算符出棧 到 最近一次左括號
sym.pop(); //最近一次左括號出棧
i++; //跳過當前右括號
}
else if (isdigit(s[i])){ //數字,計算值
int x=0;
while (isdigit(s[i])) x=10*x+s[i++]-'0';
num.push(x); //數字入數字棧
}
else { //運算符
while (!sym.empty() && lev[s[i]]<=lev[sym.top()]) calculate();
//當前運算符s[i] <= 運算符棧頂運算符 運算符出棧
sym.push(s[i]); //當前運算符入棧
i++; //跳過當前運算符
}
}
while (!sym.empty()) calculate(); //清空運算符棧
cout<<num.top()<<endl;
return 0;
}