杭电oj1237:简单计算器(水而不水)

简单计算器

题目链接

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

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;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值