[HDU1237]-简单计算器

简单计算器

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 18228    Accepted Submission(s): 6416

Problem Description
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
 

Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
 

Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
 

Sample Input
  
  
1 + 2 4 + 2 * 5 - 7 / 11 0  

Sample Output
  
  
3.00 13.36
题目描述:表达式求值问题。
谈谈解题过程吧:
由于本人是菜菜,所以很弱,看到这个题是表达式求值,马上就用教科书上表达式求值的模板,我们学校用的是<<数据结构教程>>(第4版)李春葆的书,敲了半天,交上去wa了这题意其实不怎么明显,他没说运算数的精度,如果是2个超过60个字符的数字他们之间的运算double可能会精度受损,所以我就想用java大精度来写,我又用java写了半天,真真切切花了不少时间把c++代码给转换成了java,不过结果是wa,没办法了,于是借鉴了大神的解题思路,结果半小时不到就a了,当然之前我的想法是错了,她不会给你大数的运算,真是膜拜啊!根据大神的思路,代码如下:
//c++解法,没有括号的
#include <cstdio>
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
const int maxn=10001;
double num[maxn];
int main()
{
	double d;
	char c;
	// freopen("data.in","r",stdin);
	while(true)
	{
		memset(num,0,sizeof(num));
		int p = 0;
		cin >> d;
		num[0]=d;
		c=getchar();
		if(d==0&&c=='\n')
			break;
		while(true)
		{
			cin>>c>>d;
			if(c == '/')
				num[p]/=d;
			else if(c == '*')
				num[p]*=d;
			else if(c == '-')
				num[++p]-=d;
			else
				num[++p]+=d;
			if(getchar()=='\n')
				break;
		}
		double res=0;
		for(int i = 0;i <= p;++ i)
			res += num[i];
		cout << fixed << setprecision(2) << res << endl;
	}
	return 0;
}
这种暴力简洁的代码,一目了然,也通熟易懂,耗时也少。

在用这种思想做完后,既然没有大数的处理,于是反过头去做之前的自己代码,我无意间改了下我的输入,结果交上去就a了,居然是这种低级错误,原来是我判断结束时没有判断其长度为1,ac代码如下
//一般解法,没有大数
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 2000;
const int MaxOp=5;
struct op 											//设定运算符优先级
{
	char ch;										//运算符
	int pri;										//优先级
}lpri[MaxOp]={{'=',0},{'+',2},{'-',2},{'*',4},{'/',4}},
rpri[MaxOp]={{'=',0},{'+',1},{'-',1},{'*',3},{'/',3}};
int leftpri(char op)								//求左运算符op的优先级
{
	for(int i = 0;i < MaxOp;++ i)
		if(lpri[i].ch==op)
			return lpri[i].pri;
}
int rightpri(char op)								//求有运算符op的优先级
{
	for(int i = 0;i < MaxOp;++ i)
		if(rpri[i].ch==op)
			return rpri[i].pri;
}
bool INOp(char ch)									//判断ch是否为运算符
{
	if(ch=='+'||ch=='-'||ch=='*'||ch=='/')
		return true;
	return false;
}
int Precede(char op1,char op2)						//op1和op2运算符优先级的比较结果
{

	if(leftpri(op1)<rightpri(op2))
		return -1;
	else
		return 1;
}
void trans(char *exp,char *postexp)					//将exp表达式转换成后缀表达式
{
	struct p
	{
		char data[maxn];							//存放运算符
		int top;
	}op;
	int i = 0;										//i作为postexp的下标
	op.top = -1;
	op.top++;
	op.data[op.top] = '=';							//将'='进栈
	while(*exp!='\0')								//exp表达式未扫描时循环
	{
		if(!INOp(*exp))								//为数字字符的情况
		{
			while(*exp >= '0'&&*exp<='9')			//判断为数字
			{
				postexp[i++]=*exp;
				exp++;
			}
			postexp[i++]='#';						//用'#'标志一个数值串结束
		}
		else										//为运算符的情况
		{
			switch(Precede(op.data[op.top],*exp))
			{
				case -1:							//栈顶运算符的优先级低
					op.top++;op.data[op.top]=*exp;
					exp++;							//继续扫描其他字符
					break;
				case 1:								//退栈并输出到postexp中
					postexp[i++]=op.data[op.top];
					op.top--;
					break;
			}
		}
	}
	while(op.data[op.top]!='=')						//此时exp扫描完毕,退栈到'='为止
	{
		postexp[i++] = op.data[op.top];
		op.top--;
	}
	postexp[i]='\0';								//给postexp表达式添加结束标识
}
double compvalue(char *postexp)						//计算后缀表达式的postexp的值
{
	struct
	{
		double data[maxn];							//存放数值
		int top;									//栈指针
	}st;											//定义一个运算数栈
	double a,b,c,d;
	st.top=-1;
	while(*postexp!='\0')							//postexp字符串未扫描时完成循环
	{
		switch(*postexp)
		{
			case '+':								//判定'+'
				a = st.data[st.top];
				st.top--;							//退栈并取值a
				b = st.data[st.top];
				st.top--;							//退栈并取值b
				c = a + b;							//计算c
				st.data[++st.top]=c;				//将计算结果进栈
				break;
			case '-':								//判定'-'
				a = st.data[st.top];
				st.top--;							//退栈并取值a
				b = st.data[st.top];
				st.top--;							//退栈并取值b
				c = b - a;							//计算c
				st.data[++st.top]=c;				//将计算结果进栈
				break;
			case '*':								//判定'*'
				a = st.data[st.top];
				st.top--;							//退栈并取值a
				b = st.data[st.top];
				st.top--;							//退栈并取值b
				c = a * b;							//计算c
				st.data[++st.top]=c;				//将计算结果进栈
				break;
			case '/':								//判定'/'
				a = st.data[st.top];				
				st.top--;							//退栈并取值a
				b = st.data[st.top];
				st.top--;							//退栈并取值b
				if(a!=0)							//判断被除数不能为0
				{								
					c = b/a;						//计算c
					st.data[++st.top]=c;			//将计算结果进栈
				}
				break;
			default:								//处理数字字符
				d = 0;								//将连续的数字字符转换成对应的数值存放到d中
				while(*postexp >= '0'&&*postexp <= '9')//判定为数字字符
				{
					d=10*d+*postexp-'0';
					postexp++;
				}
				st.data[++st.top]=d;
		}
		postexp++;									//继续处理其他字符
	}
	return st.data[st.top];
}
int main()
{
	char exp[maxn];
	char c[maxn];
	int cnt=0;
	freopen("data.in","r",stdin);
	while(true)
	{
		gets(c);
		bool flag=true;
		int len = strlen(c);
		if(c[0]=='0'&&len==1)
			break;
		cnt=0;
		for(int i = 0;c[i];++ i)
			if(c[i]!=' ')
				exp[cnt++]=c[i];
		exp[cnt]='\0';
		char postexp[maxn];
		trans(exp,postexp);
		printf("%.2lf\n",compvalue(postexp));
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值