简单计算器
Problem Description
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
Sample Input
1 + 2
4 + 2 * 5 - 7 / 11
0
Sample Output
3.00
13.36
如果只想看AC的代码,请滑到最后,看最后一个代码块的代码即可。
这个道题虽然是一道水题,但是做起来也是要命啊!竟然写了将近一个小时,归根到底还是自己太菜!!!
首先遇到的第一个问题,就是如何读取的问题!所以一开始我是这样写的:
#include<iostream>
#include<cstring>
using namespace std;
double ans[200];
int main()
{
//freopen("in.txt", "r", stdin);
double num;
char c;
while(cin>>num, num!=0)
{
memset(ans, 0, sizeof(ans));
int counts = 0;
ans[counts++] = num;
int flag = 0;
while(1)
{
switch(getchar())
{
case '*':{
cin>>num;
ans[counts-1] = ans[counts-1] * num;
break;
}
case '/':{
cin>>num;
ans[counts-1] = 1.0 * ans[counts-1] / num;
break;
}
case '-':{
cin>>num;
ans[counts++] = 0 - num;
break;
}
case '+':{
cin>>num;
ans[counts++] = num;
break;
}
case '\n':{
flag = 1;
break;
}
default:break;
}
if(flag)
break;
}
double sum = 0.0;
for(int i=0;i<counts;i++)
sum += ans[i];
printf("%.2lf\n", sum);
}
return 0;
}
写完之后,那么问题来了,遇到下面的样例直接就死翘翘了。
0 * 6
0 / 3
因为while(cin>>num, num!=0){}
直接就给判死了啊!啊,我的天。
不服气的我,立马对它进行改进,所以第二版就出来了。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//freopen("in.txt", "r", stdin);
string str;
getline(cin, str);
while(str != "0")
{
int len = str.length();
double *ans = new double[len];//存整数
char *symbol = new char[len];//存符号
int sym_counts = 0;
int ans_counts = 0;
ans[ans_counts++] = str[0] - '0';
int i=2;
while(i < len)
{
switch(str[i])
{
case '*':{
ans[ans_counts-1] = ans[ans_counts-1] * (str[i+2] - '0');
break;
}
case '/':{
ans[ans_counts-1] = 1.0 * ans[ans_counts-1] / double(str[i+2] - '0');
break;
}
case '-':{
symbol[sym_counts++] = '-';
ans[ans_counts++] = str[i+2] - '0';
break;
}
case '+':{
symbol[sym_counts++] = '+';
ans[ans_counts++] = str[i+2] - '0';
break;
}
}
i += 4;
}
double sum = ans[0];
for(i=0;i<sym_counts;i++)
{
if(symbol[i] == '+')
sum += ans[i+1];
else
sum -= ans[i+1];
}
printf("%.2lf\n", sum);
getline(cin, str);
delete []symbol;
delete []ans;
}
return 0;
}
写完之后,测试了样例都通过了,心里高兴了一把。胆小,没敢提交,又写了几个样例测试了几把。问题又来了,哇哇哇…
4 + 2 * 5 - 7 / 11
竟然结果是7.00 !!!!!
可爱的bug,mmp我又来了。
最后发现是
case '/':{
ans[ans_counts-1] = 1.0 * ans[ans_counts-1] / double(str[i+2] - '0');
break;
}
明明是11,自己写的程序竟然按1来计算的。
想让我就此放弃!!!没门。。。一个字“改”:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//freopen("in.txt", "r", stdin);
string str;
getline(cin, str);
while(str != "0")
{
int len = str.length();
double *ans = new double[len];
char *symbol = new char[len];
int sym_counts = 0;
int ans_counts = 0;
int i=0, temp=0;
while(i < len &&str[i] != ' ')
{
temp = (temp * 10) + (str[i] - '0');
i++;
}
ans[ans_counts++] = temp;
i += 1;
char c;
while(i < len)
{
c = str[i];
i += 2;
temp = 0;
while(i<len && str[i] != ' ')
temp = (temp * 10) + (str[i++] - '0');
switch(c)
{
case '*':{
ans[ans_counts-1] = ans[ans_counts-1] * temp;
break;
}
case '/':{
ans[ans_counts-1] = 1.0 * ans[ans_counts-1] / temp;
break;
}
case '-':{
symbol[sym_counts++] = '-';
ans[ans_counts++] = temp;
break;
}
case '+':{
symbol[sym_counts++] = '+';
ans[ans_counts++] = temp;
break;
}
}
i += 1;
}
double sum = ans[0];
for(i=0;i<sym_counts;i++)
{
if(symbol[i] == '+')
sum += ans[i+1];
else
sum -= ans[i+1];
}
printf("%.2lf\n", sum);
getline(cin, str);
delete []symbol;
delete []ans;
}
return 0;
}
这一版提交上去终于AC了。不容易啊,下边是精简版本(对代码精简了一下):
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//freopen("in.txt", "r", stdin);
string str;
getline(cin, str);
while(str != "0")
{
int len = str.length();
double *ans = new double[len];
int ans_counts = 0, i=0, temp=0;
while(i < len &&str[i] != ' ')//取第一个整数
temp = (temp * 10) + (str[i++] - '0');
ans[ans_counts++] = temp;
char c;
while(i < len)
{
c = str[++i];//str[i]为空格,所以需要先自增
i += 2;
temp = 0;
while(i < len && str[i] != ' ')//取下一个整数
temp = (temp * 10) + (str[i++] - '0');
switch(c)
{
case '*':{
ans[ans_counts-1] = ans[ans_counts-1] * temp;
break;
}
case '/':{
ans[ans_counts-1] = 1.0 * ans[ans_counts-1] / temp;
break;
}
case '-':{
ans[ans_counts++] = 0 - temp;
break;
}
case '+':{
ans[ans_counts++] = temp;
break;
}
}
}
for(i=1;i<ans_counts;i++)
ans[i] += ans[i-1];
printf("%.2lf\n", ans[ans_counts-1]);
getline(cin, str);
delete []ans;
}
return 0;
}
更新:把这种题模板化,也就是用栈来做(中缀、后缀表达式)。
#include<iostream>
#include<stack>
#include<queue>
#include<map>
using namespace std;
struct Node{
double num; //操作数,可能会出现小数,所以是double
char op;//操作符
bool isNum; //isNum为true,代表是操作数
Node(){isNum = true;}
};
stack<Node> s;
queue<Node> q;
map<char, int> mp;//运算符优先级
void change(string str) //将中缀表达式转换为后缀表达式 ,存放在栈s中
{
int len = str.length();
for(int i=0; i < len; i++)
{
Node node;
if(str[i] == ' ')
continue;
if(str[i] >= '0' && str[i] <= '9'){//是操作数
// node.isNum = true;
node.num = str[i] - '0';
while((i+1 < len) && str[i+1] >= '0' && str[i+1] <= '9'){
i++;
node.num = node.num * 10 + (str[i] - '0');
}
//送到后缀表达式中
q.push(node);
}
else{//操作符
node.isNum = false;
node.op = str[i];
//判断
while(!s.empty() && mp[s.top().op] >= mp[str[i]]){
q.push(s.top());
s.pop();
}
s.push(node);
}
}
while(!s.empty()){
q.push(s.top());
s.pop();
}
}
double cal()//计算后缀表达式
{
Node first, last;
while(!q.empty()){
if(q.front().isNum)//操作数
s.push(q.front());
else{//操作符
last = s.top();
s.pop();
switch(q.front().op)
{
case '+':
s.top().num += last.num;
break;
case '-':
s.top().num -= last.num;
break;
case '*':
s.top().num *= last.num;
break;
case '/':
s.top().num /= last.num;
break;
}
}
q.pop();
}
return s.top().num;
}
int main()
{
mp['+'] = mp['-'] = 1;
mp['*'] = mp['/'] = 2;
string str;
while(getline(cin, str), str!="0")
{
while(!s.empty()) s.pop();
change(str);
printf("%.2lf\n", cal());
}
return 0;
}