时间限制: 3000 ms | 内存限制: 65535 KB
难度: 4
描述
ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧。
比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数)
输入
第一行输入一个整数n,共有n组测试数据(n<10)。
每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束。这个表达式里只包含+-*/与小括号这几种符号。其中小括号可以嵌套使用。数据保证输入的操作数中不会出现负数。
数据保证除数不会为0.
这是我们oj的一道题,但是它非常有局限性,就是当表达式中间存在空格的时候,如何正常计算表达式的值。
无法克服表达式中有空格的程序:
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include<stack>
#include<string.h>
using namespace std;
bool IsOperator(char ch);
char Precede(char opr1, char opr2);
double Operate(double opnd1, char op, double opnd2);
int ConvertToIndex(char opr);
/**
这个是用来判断一个字符是不是
操作符的
*/
bool IsOperator(char ch)
{
if (ch == '+' || ch == '-' ||
ch == '*' || ch == '/' ||
ch == '(' || ch == ')' || ch == '=')
return true;
else
return false;
}
//运算符的优先关系
//'+', '-', '*', '/', '(', ')', '#'
char OprRelation[7][7] = {{'>', '>', '<', '<', '<', '>', '>'}, //'+'
{'>', '>', '<', '<', '<', '>', '>'}, //'-'
{'>', '>', '>', '>', '<', '>', '>'}, //'*'
{'>', '>', '>', '>', '<', '>', '>'}, //'/'
{'<', '<', '<', '<', '<', '=', ' '}, //'('
{'>', '>', '>', '>', ' ', '>', '>'}, //')'
{'<', '<', '<', '<', '<', ' ', '='}
};//'#'
/**
这个是用来获取每一个操作符的优先级
*/
int ConvertToIndex(char opr)
{
int index;
switch (opr)
{
case '+':
index = 0;
break;
case '-':
index = 1;
break;
case '*':
index = 2;
break;
case '/':
index = 3;
break;
case '(':
index = 4;
break;
case ')':
index = 5;
break;
case '=':
index = 6;
break;
}
return index;
}
/**
这个是用来获取连个字符的优先级
*/
char Precede(char opr1, char opr2)
{
int index1 = ConvertToIndex(opr1);
int index2 = ConvertToIndex(opr2);
return OprRelation[index1][index2];
}
/**
这个是用来对两个数进行求值
*/
double Operate(double opnd1, char op, double opnd2)
{
double ret;
switch(op)
{
case '+':
ret = opnd1 + opnd2;
break;
case '-':
ret = opnd1 - opnd2;
break;
case '*':
ret = opnd1 * opnd2;
break;
case '/':
ret = opnd1 / opnd2;
break;
}
return ret;
}
//算符优先算法
double CaculateExpression(string exp)
{
stack<char> optr; //只处理+ - # / ()运算
stack<double> opnd; //只处理0-9的整数运算
char ch;
int i = 0;
optr.push('=');
ch = exp[i++];
bool flag = true;
//如果##配对,表达式求值完成
while (flag&&(ch != '=' || optr.top() != '='))
{
if (!IsOperator(ch))
{
string f,g;
f=exp[i-1];
g.append(f);
while(!IsOperator(exp[i]))
{
f=exp[i];
g.append(f);
++i;
}
double value = atof(g.c_str());
//操作数入栈
opnd.push(value);
ch = exp[i++];
}
else
{
//比较栈顶操作符和新取得的操作符的优先关系
cout<<optr.top()<<" "<<ch<<endl;
cout<<Precede(optr.top(),ch)<<endl;
switch (Precede(optr.top(), ch))
{
case '<'://栈顶优先权低
optr.push(ch);
ch = exp[i++];
break;
case '='://括号配对,栈顶括号弹出
optr.pop();
if(exp.length()==i)
{
flag=false;
}
else
{
ch = exp[i++];
}
break;
case '>'://栈顶优先权高,先弹出,计算,结果操作数入栈
char op = optr.top();
optr.pop();
double num2 = opnd.top();//第二个操作数在前
opnd.pop();
double num1 = opnd.top();
opnd.pop();
double ret = Operate(num1, op, num2);
opnd.push(ret);
break;
}
}
}//end of while
// cout<<ch<<" "<<optr.top()<<endl;
//操作数栈的唯一元素即为计算结果
return opnd.top();
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
char str[1000];
scanf("%s",str);
// strcat(str,"#");
string f;
f=str;
//cout<<atof(f.c_str())<<endl;
printf("%.2lf\n",CaculateExpression(f));
}
return 0;
}
克服表达式中有空格的程序:
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<stack>
#include<stdlib.h>
using namespace std;
stack<double> num;
stack<char> optr;
// + - * / ( ) =
char opt[7][7]= {'>','>','<','<','<','>','>', // +
'>','>','<','<','<','>','>',// -
'>','>','>','>','<','>','>',// *
'>','>','>','>','<','>','>',// /
'<','<','<','<','<','=','>',// (
'>','>','>','>','>','>','>', // ) // 不可能放进去的
'<','<','<','<','<','<','=' // =
};
double rel_two(double a,char b,double c)
{
switch(b)
{
case '+':
return a+c;
case '-':
return a-c;
case '*':
return a*c;
case '/':
return a/c;
}
}
bool is_optr(char& ch)
{
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='=')
{
return true;
}
else
return false;
}
int pri(char _pri)
{
switch(_pri)
{
case '+':
return 0;
case '-':
return 1;
case '*':
return 2;
case '/':
return 3;
case '(':
return 4;
case ')':
return 5;
case '=':
return 6;
}
}
char priority(char a,char b)
{
int a1,b1;
a1=pri(a);
b1=pri(b);
return opt[a1][b1];
}
double cal(string exp)
{
optr.push('=');
int i=0;
char ch=exp[i++];
while((optr.top()!='=' || ch!='=' )&& ch!='\0')
{
if(ch!=' ')
{
if(is_optr(ch))
{
// cout<<ch<<endl;
cout<<optr.top()<<" "<<ch<<endl;
cout<<priority(optr.top(),ch)<<endl;
switch(priority(optr.top(),ch))
{
case '<':
optr.push(ch);
// cout<<optr.top()<<" "<<ch<<endl;
ch=exp[i++];
break;
case '=':
optr.pop();
ch=exp[i++];
break;
case '>':
char ch1;
ch1=optr.top();
// cout<<ch1<<endl;
optr.pop();
double a,b;
b=num.top();
num.pop();
a=num.top();
// cout<<a<<b<<endl;
num.pop();
num.push(rel_two(a,ch1,b));
// cout<<num.top()<<endl;
// ch=exp[i++]; // 栈顶元素需要依次和ch比较优先级
break;
}
}
else
{
string p,q;
q=ch;
p.append(q);
// while(!is_optr(ch)&&ch!=' ')
while(!is_optr(exp[i])&&exp[i]!=' ')
{
// q=exp[i]; // error occur!
p.append(q);
i++;
}
// cout<<p<<endl;
ch=exp[i++];
num.push(atof(p.c_str()));
// cout<<atof(p.c_str())<<endl;
// cout<<p<<endl;
}
}
else
{
ch=exp[i++];
}
}
return num.top();
}
int main()
{
int n;
scanf("%d",&n);
getchar();
while(n--)
{
char s[100];
gets(s);
string s1;
s1=s;
// cout<<s<<endl;
// cout<<atoi(s1.c_str())<<endl;
cout<<cal(s1.c_str())<<endl;
}
}
输出结果: