简单版(无括号)
Sample Input:
1 + 1 / 1 * 1 - 1
Sample Output:
1.00
步骤
- 由输入的运算时字符串提取数字与运算符,从而得到中缀表达式
- 由中缀表达式转换为后缀表达式
- 通过stack来计算后缀表达式
参考代码
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <vector>
#include <map>
#include <cmath>
using namespace std;
map<string, int> m; //运算符优先级
bool judgeNum(string str) //判断是不是数字
{
if(str[0] >= '0' && str[0] <= '9')
return true;
return false;
}
void GetMid(const string str, vector<string> &v) //由输入的字符串提取中缀表达式
{
string s0;
for (int i = 0; i < str.size(); i++)
{
if (str[i] == ' ')
continue;
s0.clear();
if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
{
s0 += str[i], v.push_back(s0);
continue;
}
bool tag = false;
while (str[i] >= '0' && str[i] <= '9')
s0 += str[i], tag = true, i++;
if (tag)
v.push_back(s0), i--;
}
}
void GetBack(const vector<string> v, vector<string> &vb) //由中缀表达式Get后缀表达式(简易版, 不带括号)
{
stack<string> s;
for (int i = 0; i < v.size(); i++)
{
/*遇到数字直接加入后缀序列*/
if (judgeNum(v[i]))
{
vb.push_back(v[i]);
continue;
}
/*遇到运算符, 进一步判断*/
if (s.empty() || m[v[i]] < m[s.top()])
s.push(v[i]);
else{
while (!s.empty() && m[v[i]] >= m[s.top()])
vb.push_back(s.top()), s.pop();
s.push(v[i]);
}
}
/*栈中剩余运算符的直接加入后缀表达式*/
while (!s.empty())
vb.push_back(s.top()), s.pop();
}
bool Calculate(const vector<string> vb, double &ans) //计算后缀表达式
{
stack<double> s;
for (int i = 0; i < vb.size(); i++)
if(judgeNum(vb[i])) //如果是数字
s.push(stod(vb[i]));
else{
double a, b;
b = s.top(), s.pop();
a = s.top(), s.pop();
if(vb[i] == "+")
a += b;
else if(vb[i] == "-")
a -= b;
else if(vb[i] == "*")
a *= b;
else{
if(abs(b) <= 1e-6)
return false;
a /= b;
}
s.push(a);
}
//cout << s.size() << endl;
ans = s.top();
return true;
}
int main()
{
double ans;
string str;
vector<string> v, vb; //中缀表达式与后缀表达式
getline(cin, str);
/*初始化表示运算符的优先级*/
m["+"] = m["-"] = 2;
m["*"] = m["/"] = 1;
GetMid(str, v);
GetBack(v, vb);
if (!Calculate(vb, ans))
cout << "Cannot be divided by 0" << endl;
else
printf("%.2f\n", ans);
system("pause");
return 0;
}
/*
2+1-2*3-4+5
*/
标准版(有括号)
编写程序,从键盘输入一个合法的表达式,对该表达式进行求值并输出,为降低题目难度,特做如下要求:
运算数均为整型数(即不带小数点)
运算符只支持加减乘除四种(+、-、*、/)以及小括号(())
计算规则为实型数运算规则,例如1/2=0.5
输出计算结果保留两位小数(四舍五入)
表达式中不允许出现如下情况
- 空字符串
- 错误的运算符
- 错误的运算数
- 括号不匹配
- 空括号
- 连续的运算符,例如–5
- 运算符为正数时,其符号+必须省略,例如+2+4定义为非法,而负数时为合法,例如-2+4
- 程序要能处理表达式中间出现的空格(输入表达式中存在空格为合法情况)
- 其他不符合表达式书写规则的情况
输入格式:
从键盘输入一行表达式。例如2+3*(5 -6 / 4)/3 +26-300*3/29
输出格式:
有以下三种输出结果:
表达式不合法时,输出Wrong Format
出现无法计算情况时(例如除0),输出输入表达式 = NaN
能够正确运算时,输出输入表达式 = 计算结果
输入样例1:
在这里给出一组输入。例如:
2+3*(5 -6 / 4)/3 +26-300*3/29
输出样例1:
在这里给出相应的输出。例如:
2+3*(5 -6 / 4)/3 +26-300*3/29 = 0.47
输入样例2:
在这里给出一组输入。例如:
2+3- 5 / 0
输出样例2:
在这里给出相应的输出。例如:
2+3- 5 / 0 = NaN
输入样例3:
在这里给出一组输入。例如:
((2-3/4*5/4 +8-0.4)/100-003*5
输出样例3:
在这里给出相应的输出。例如:
Wrong Format
解题思路
(摘自下文参考博客)
代码:
#include <iostream> //表达式求值(带括号)
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <stack>
#include <cmath>
using namespace std;
bool GetMid(string str, vector<string> &vm) //得到中缀表达式, 返回判断表达式是否合法
{
string s0;
stack<string> s;
for (int i = 0; i < str.size(); i++)
{
bool tag = false;
while (str[i] >= '0' && str[i] <= '9' && i < str.size()) //如果是数字
tag = true, s0 += str[i++];
if(tag)
vm.push_back(s0), s0.clear(), i--;
if(str[i] != ' ' && !tag) //如果是操作符
{
s0 += str[i];
vm.push_back(s0);
s0.clear();
}
}
int cnt = 0;
for (int i = 0; i < vm.size(); i++)
{
if(vm[i] == "(" || vm[i] == ")")
{
if(vm[i] == "(")
s.push(vm[i]);
else{
if(s.empty() || s.top() == ")")
return false;
if(s.top() == "(")
s.pop();
}
continue;
}
cnt++;
//cout << cnt << " " << vm[i] << endl;
if (!(cnt % 2) && vm[i][0] >= '0' && vm[i][0] <= '9' || cnt % 2 && !(vm[i][0] >= '0' && vm[i][0] <= '9'))
return false;
}
if(!s.empty())
return false;
// for (int i = 0; i < vm.size(); i++)
// cout << vm[i] << " ";
// cout << endl;
return true;
}
void Mid_to_back(const vector<string> vm, vector<string> &vb) //中缀表达式得后缀表达式
{
stack<string> s;
map<string, int> m; //运算符优先级
m["*"] = m["/"] = 1;
m["+"] = m["-"] = 2;
for (int i = 0; i < vm.size(); i++)
if(vm[i][0] >= '0' && vm[i][0] <= '9') //如果是数字直接输出
vb.push_back(vm[i]);
else{
if(vm[i] == "(")
s.push(vm[i]);
else if(vm[i] == ")")
{
// cout << ")" << endl;
while (!s.empty() && s.top() != "(")
{
//cout << s.top() << endl;
vb.push_back(s.top()); //输出
s.pop();
}
//cout << s.top() << endl;
if(!s.empty() && s.top() == "(")
s.pop();
}
else{
if(s.empty() || m[vm[i]] < m[s.top()] || s.top() == "(")
s.push(vm[i]);
else{
while (!s.empty() && m[vm[i]] >= m[s.top()] && s.top() != "(") //
vb.push_back(s.top()), s.pop();
s.push(vm[i]);
}
}
}
while (!s.empty())
vb.push_back(s.top()), s.pop();
// for (int i = 0; i < vb.size(); i++)
// cout << vb[i] << " ";
// cout << endl;
}
bool Calculate_back(vector<string> vb, double &ans) //运用stack计算后缀表达式
{
stack<double> s;
double t;
for (int i = 0; i < vb.size(); i++)
if(vb[i][0] >= '0' && vb[i][0] <= '9') //入栈
s.push(stod(vb[i]));
else{
double a, b;
b = s.top(), s.pop();
a = s.top(), s.pop();
if (vb[i] == "+")
a += b;
else if (vb[i] == "-")
a -= b;
else if (vb[i] == "*")
a *= b;
else{
if (abs(b) <= 1e-6)
return false;
a /= b;
}
s.push(a);
}
if(!s.empty())
ans = s.top();
return true;
}
int main()
{
string str;
double ans;
vector<string> vm, vb; //用于提取字符串所表示的中缀表达式, 及转换的后缀表达式
getline(cin, str);
if(GetMid(str, vm))
{
Mid_to_back(vm, vb);
cout << str << " = ";
if(Calculate_back(vb, ans))
printf("%.2f\n", ans);
else
cout << "NaN";
}
else
cout << "Wrong Format" << endl;
system("pause");
return 0;
}
/*
1)如果遇到操作数,我们就直接将其输出。
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
*/
参考博客:
https://blog.csdn.net/ssjhust123/article/details/8001651