读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入:
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;
}