中綴表示式轉換成字尾表示式,進行簡單表示式的計算
阿新 • • 發佈:2019-02-05
分析:
- 步驟一:中綴表示式轉換為字尾表示式
- 設立一個操作符棧,用來臨時存放操作符;設定一個佇列用以存放字尾表示式序列。
- 從左至右遍歷中綴表示式,如果遇到運算元(需要注意的是運算元可能不止一位,因此需要一位位的讀入然後合併成整數)就將其加入到字尾序列中。
- 如果遇到操作符,如果是左括號‘(’就直接壓入棧中,如果是右括號‘)’就依次彈出棧中元素直至左括號出現。否則將其與棧頂元素比較優先順序大小。如果該操作符的優先順序更大,那麼直接壓入棧中。否則每次將棧頂元素彈出,依次加入佇列,直至操作符優先順序大於了新的棧頂元素的優先順序。
- 重複上述步驟直至遍歷完中綴表示式,如果最後棧中還有元素,那麼就依次彈出,加入到佇列中,直至棧空
- 步驟二:計算字尾表示式
從左至右掃描字尾表示式,如果是運算元,那麼壓入棧中,如果是操作符那麼就從棧中彈出兩個運算元(注意,這兩運算元和操作符的結合順序是固定的,先彈出的是第二運算元結合到操作符的右邊,後彈出的是第一運算元結合到操作符的左邊)結合操作符進行運算。並將得到的新的運算元壓入到棧中。反覆以上步驟直到掃描完字尾表示式。那麼最後剩下的就是最終的接過了。
注意:本程式關於括號的處理那一塊有問題。我現在還很菜沒有找到問題在哪,待以後再改。
#include<iostream>
#include<stack>
#include<queue>
#include<string>
#include<map>
#include<fstream>
using namespace std;
struct node{ //定義結構體,該結構體用於儲存每次處理的字元
char op; //如果是操作符,存入到op中,並且要將flag置為false
double data; //如果是運算元,存入到data中,並且要將flag置為true
bool flag;
};
stack<node> s; //操作符棧,存放操作符的臨時工作棧。
queue<node> q; //字尾表示式佇列
map<char,int> op; //操作符優先順序
void change(string str){
op['+']=op['-']=1; //輸入操作符優先順序
op['*']=op['/']=2;
for(int i=0;i<str.length();){
node temp;
if(str[i]>='0'&&str[i]<='9'){ //如果是運算元的話
temp.flag =true; //標記置為true
temp.data=str[i++]-'0'; //儲存到臨時結構體temp中
while(i<str.length() && str[i]>='0' && str[i]<='9'){ //因為數字可能不止一位,因此迴圈至不是數字為止
temp.data=temp.data*10+(str[i]-'0'); //組成整數
i++;
}
q.push(temp); //將該運算元扔進字尾序列的佇列中
}
else if(str[i]=='('){ //之前一直以為我這一塊處理括號的寫錯了。。。。。後來發現程式碼沒錯。。。是因為自己輸入的是中文括號。。。
temp.flag =false;
temp.op =str[i]; //是左括號直接壓入佇列
s.push(temp);
i++;
}
else if(str[i]==')'){ //終於等到了右括號
while(s.top().op!='('){ //將棧裡面的操作符彈出到字尾表示式中,知道碰到了左括號
q.push(s.top());
s.pop();
}
s.pop() ; //扔掉左括號
i++;
}
else{
temp.flag =false; //如果是操作符,那麼標記置為false
while(!s.empty()&&op[str[i]]<=op[s.top().op]){ //只有當該操作符的優先順序高於棧頂元素的優先順序,才壓入棧內
q.push(s.top()); //否則將棧頂元素彈出,壓入到佇列中
s.pop() ;
}
temp.op=str[i];
s.push(temp);
i++;
}
}
while(!s.empty()){ //最後如果操作符棧還不空的話。依次彈出壓入到佇列中
q.push(s.top());
s.pop() ;
}
}
double cal(){ //計算字尾表示式
node cur,temp;
double temp1,temp2; //第一運算元,第二運算元
while(!q.empty()){
cur=q.front(); //取得隊首元素
q.pop() ;
if(cur.flag==true){ //如果是運算元,壓入棧中
s.push(cur);
}
else{ //如果是操作符
temp2=s.top().data ; //取出第二運算元
s.pop() ;
temp1=s.top().data ; //取出第一運算元
s.pop() ;
temp.flag =true; //臨時存放結果的temp,當然是新的運算元
if(cur.op =='+'){
temp.data =temp1+temp2;
}
else if(cur.op =='-'){
temp.data =temp1-temp2;
}
else if(cur.op =='*'){
temp.data =temp1*temp2;
}
else{
temp.data =temp1/temp2;
}
s.push(temp);
}
}
return s.top().data; //最後棧頂剩的唯一一個元素就是最終的結果了
}
int main()
{
string str;
//fstream fin("C://Users/haha/Desktop/input.txt",ios::in); //筆者當時從檔案中讀取的表示式
cin>>str;
change(str); //改成字尾表示式
cout<<cal(); //計算結果。
}