读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入:
1 + 2
4 + 2 * 5 – 7 / 11
0
输出:
3.00
13.36
这种类型题写了很多,但每次变化一点点就会卡很久,而且中缀转后缀也一直不熟练。。今天再用两种方法总结一次
方法一:后缀式法
相比于之前写的中缀式转后缀式,遇到的问题有:
- 常量不再用a,b,c表示,而是具体的常数,这就导致不再能用一个字符栈来存储后缀表达式,必须将操作数从字符串中提取并组合起来,再用操作数栈和运算符栈分开存放。
- 总是思维惯性的想着求出后缀式之后,再用一个栈对后缀式求值,然而在不能用一个字符栈存后缀式的情况下,这是很复杂的。其实可以在每次向后缀式添加运算符时直接求值啊!
- 56和61两行写错了,在vs下才找出问题
#include<bits/stdc++.h>
using namespace std;map<char,int> isp;
map<char,int> icp;
stack<double> num; //操作数栈
stack<char> s; //运算符栈
string str; //键盘输入的中缀式
string post; //后缀式 但在本题中,每次向后缀式添加运算符时 改为直接计算即可,故无需用到后缀式 int getNum(int i)
{double numb = 0;while(str[i] >= '0' && str[i] <= '9') {numb = numb * 10 + str[i++] - '0'; }num.push(numb);return i;
}void cal(char op)
{double s2 = num.top();num.pop();double s1 = num.top();num.pop();
// cout << s1 << op << s2 << endl;switch(op){case '+':num.push(s1+s2); break;case '-':num.push(s1-s2); break;case '*':num.push(s1*s2); break;case '/':num.push(s1/s2); break;}
}int main()
{isp['*'] = 5;isp['/'] = 5;isp['+'] = 3;isp['-'] = 3;icp['*'] = 4;icp['/'] = 4;icp['+'] = 2;icp['-'] = 2;while(getline(cin,str)){//num.clear(); s.clear(); 栈好像没有clear()方法,不过不清空也问题不大 for(int i=0;i<str.length();i++){if(str[i] == ' ')continue;else if(str[i] >= '0' && str[i] <= '9')i = getNum(i); //返回的i指向操作数后的空格 ,操作数存在操作数栈中 else{ //运算符 if(s.empty() || icp[str[i]] > isp[s.top()])s.push(str[i]);else{while(!s.empty() && icp[str[i]] < isp[s.top()]){ //!s.empty()必须写在前面(思考原因)// post += s.top();//要求输出后缀式时的写法 cal(s.top()); //直接计算的写法 s.pop();}s.push(str[i]); //差点忘记 } } }while(!s.empty()){cal(s.top());// post += s.top();//s.pop();}printf("%.2f\n",num.top()); //栈顶元素即为最终答案 }
}
方法二:直接扫描
这种方法很贴近正常思维,先对*/运算,再对+ -运算,最后统一运算。
但问题是如果题目中还要求考虑括号对优先级的影响,怕是就无能为力了,但不失为一个好方法。
#include<iostream>
using namespace std;
int main()
{int d = 0, pos = -1; char op = {0};double nums[201] = { 0 };while (cin>>d) //取第一个操作数{if (-1 == pos && 0 == d && '\n' == getchar()) break;nums[++pos] = d;while (cin>>op>>d) //后面每次连运算符带操作数一起取{switch (op){case '+': nums[++pos] = d; break; //加减,在下一个位置储存case '-': nums[++pos] = -d; break;case '*': nums[pos] *= d; break; //乘除,就在原地处理case '/': nums[pos] /= d; break;}}double sum = 0; while (pos >= 0) sum += nums[pos--]; //最后统一进行加运算printf("%.2f\n", sum); getchar();}return 0;
}