分析:
- 步骤一:中缀表达式转换为后缀表达式
- 设立一个操作符栈,用来临时存放操作符;设置一个队列用以存放后缀表达式序列。
- 从左至右遍历中缀表达式,如果遇到操作数(需要注意的是操作数可能不止一位,因此需要一位位的读入然后合并成整数)就将其加入到后缀序列中。
- 如果遇到操作符,如果是左括号‘(’就直接压入栈中,如果是右括号‘)’就依次弹出栈中元素直至左括号出现。否则将其与栈顶元素比较优先级大小。如果该操作符的优先级更大,那么直接压入栈中。否则每次将栈顶元素弹出,依次加入队列,直至操作符优先级大于了新的栈顶元素的优先级。
- 重复上述步骤直至遍历完中缀表达式,如果最后栈中还有元素,那么就依次弹出,加入到队列中,直至栈空
- 步骤二:计算后缀表达式
从左至右扫描后缀表达式,如果是操作数,那么压入栈中,如果是操作符那么就从栈中弹出两个操作数(注意,这两操作数和操作符的结合顺序是固定的,先弹出的是第二操作数结合到操作符的右边,后弹出的是第一操作数结合到操作符的左边)结合操作符进行运算。并将得到的新的操作数压入到栈中。反复以上步骤直到扫描完后缀表达式。那么最后剩下的就是最终的接过了。
注意:本程序关于括号的处理那一块有问题。我现在还很菜没有找到问题在哪,待以后再改。
#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(); //计算结果。
}