[TOC]
【案例分析】
已知表达式=操作数+操作符,其中操作数是123这样的数字,操作符是运算符和界限符(如括号)。
做实验前先理清:
1.四则运算的优先性:先乘除后加减,括号优先,从左到右。
2.中缀表达式转换成后缀表达式:
- 遇到数字就直接输出到后缀表达式中,遇到操作符就判断其优先级,并将其压入栈中。
- 如果栈顶元素的优先级大于等于当前操作符,则先将栈顶元素弹出并输出到后缀表达式中,再将当前操作符压入栈中。
- 如果遇到了左括号,则直接将其压入栈中,如果遇到了右括号,则弹出栈中的元素,直到遇到了左括号为止,并将这些元素输出到后缀表达式中。
- 最后,将栈中剩余的元素依次弹出,并输出到后缀表达式中。
3.后缀表达式计算:遍历后缀表达式,如果遇到数字则直接入栈,如果遇到操作符,则弹出栈顶的两个元素,进行计算后将结果入栈。最后留在栈里的就是最终结果。
【实验过程】
1.定义
该段定义了结构体element,存放操作数num和操作符op,供stack和queue容器随时进出。
并在里面定义了布尔变量flag,用于识别中缀表达式当前字符是操作数还是操作符。
最后调用了map用于判断运算符的优先级。
1 2 3 4 5 6 7 8 9 10
| struct element{ double num; //存放操作数 char op; //存放操作符 bool flag; //true 表示操作数,false 表示操作符 };
string str; //输入的中缀表达式 stack<element>s; //操作符栈 queue<element>q; //后缀表达式队列 map<char,int>op; //判断优先级,字符到整型的映射
|
2.用map判断优先级
1<2,先乘除后加减(括号另外考虑)
1 2 3 4
| map<char,int>op; //判断优先级,字符到整型的映射
op['+'] = op['-'] = 1; op['*'] = op['/'] = 2;
|
temp.op定义为操作符栈的当前操作符
s.top().op是操作符栈的栈顶操作符
1 2 3 4 5 6 7
| while(!s.empty() && op[temp.op]<=op[s.top().op]){ //当前操作符栈的优先级低于栈顶,并且栈不为空 q.push(s.top()); s.pop(); } s.push(temp); index++; }
|
3.处理多位数问题
一位数的方法:检测到当前读取的字符是“数字”,temp转为1,表示操作数,把字符转化成阿拉伯数并进队列。
多位数的方法:读取到第一个数字后进行循环判断,一直到读取完毕或者遇到不是数字的操作符,若进入循环,那么此次读入的数为 前一个 * 10 + 现在的数字
1 2 3 4 5 6 7 8 9
| if(str[index]>='0' && str[index]<='9'){ //当前读取的是数字 temp.flag = true; temp.num = str[index++]-'0' ; //转化成数字 while(index>str.size() && str[index]>='0' && str[index]<'9'){ //处理多位数 temp.num = temp.num*10 + str[index]-'0'; index++; //下一位 } q.push(temp);//进后缀表达式队列 }
|
4.处理括号问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| if(str[index] =='(') { s.push(temp);//对左括号,直接进操作符栈 index++; //下一位 continue; }else if(str[index]==')'){ while(s.top().op!='('){ //为右括号匹配左括号 q.push(s.top()); s.pop(); //出栈元素加入到队列 } s.pop();//将左括号出栈 index++; continue; }
temp.flag=false; temp.op=str[index];
|
5.输入:去掉空格
基于map
1 2 3 4 5
| for(int i = 0; i < str.size(); i++) { //去掉空格 if(str[i] == ' ') { str.erase(str.begin() + i); } }
|
【完整代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| #include<iostream> using namespace std; #include<queue> #include<stack> #include<string> #include<map>
struct element{ double num; //存放操作数 char op; //存放操作符 bool flag; //true 表示操作数,false 表示操作符 };
string str; //输入的中缀表达式 stack<element>s; //操作符栈 queue<element>q; //后缀表达式队列 map<char,int>op; //判断优先级,字符到整型的映射
int suffix(){ //将中缀表达式str转换成后缀表达式 element temp; int index = 0; //当前位置 while(index < str.size()) { if(str[index]>='0' && str[index]<='9'){ //当前读取的是数字 temp.flag = true; temp.num = str[index++]-'0' ; //转化成数字 while(index<str.size() && str[index]>='0' && str[index]<'9'){ //处理多位数 temp.num = temp.num*10 + str[index]-'0'; index++; //下一位 } q.push(temp);//进后缀表达式队列 }else{ temp.flag = false; //当前读取的是符号 temp.op = str[index];
if(str[index] =='(') { s.push(temp);//对左括号,直接进操作符栈 index++; //下一位 continue; }else if(str[index]==')'){ while(s.top().op!='('){ //为右括号匹配左括号 q.push(s.top()); s.pop(); //出栈元素加入到队列 } s.pop();//将左括号出栈 index++; continue; }
temp.flag=false; temp.op=str[index];
while(!s.empty() && op[temp.op]<=op[s.top().op]){ //当前操作符栈的优先级低于栈顶,并且栈不为空 q.push(s.top()); s.pop(); } s.push(temp); index++; } } while(!s.empty()){ q.push(s.top()); s.pop(); } return 1; }
double cal(){ double top1,top2; element cur,temp; while(!q.empty()){ //后缀表达式队列从头依次读取 cur = q.front(); //cur记录队首 q.pop(); //出队列 if(cur.flag==true){ s.push(cur); //对操作数入栈 }else{//遇到操作符,对栈里的操作数出栈 top1 = s.top().num; s.pop(); top2 = s.top().num; s.pop(); temp.flag=true; //记录运算结果 if(cur.op == '+') temp.num = top2+top1; if(cur.op == '-') temp.num = top2-top1; if(cur.op == '*') temp.num = top2*top1; if(cur.op == '/') temp.num = top2/top1; s.push(temp);//计算结果进栈 } } return s.top().num; }
int main(){ op['+'] = op['-'] = 1; op['*'] = op['/'] = 2; getline(cin,str); while(!s.empty()){ s.pop(); //清空 } for(int i = 0; i < str.size(); i++) { //去掉空格 if(str[i] == ' ') { str.erase(str.begin() + i); } } suffix(); cout<<"计算结果为:"<<cal()<<endl; return 0; }
|