表达式求值
时间限制:3000 ms | 内存限制:65535 KB
难度:4
描述
ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧。
比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数)
输入
第一行输入一个整数n,共有n组测试数据(n<10)。
每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束。这个表达式里只包含+-*/与小括号这几种符号。其中小括号可以嵌套使用。数据保证输入的操作数中不会出现负数。
数据保证除数不会为0
输出
每组都输出该组运算式的运算结果,输出结果保留两位小数。
样例输入
2
1.000+2/4=
((1+2)*5+1)/4=
样例输出
1.50
4.00
关于中缀式转后缀式,什么是后缀式,什么是逆波兰表达式,自己百度或者等我有时间再来写
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#include<stack>
#include<math.h>
using namespace std;
//表达式求值
//中缀式转后缀式
//逆波兰表达式
int Judge(char c1,char c2)//栈顶是c1,当前字符是c2
{
if(c1=='#')//'#'是手动添加的
{
if(c2=='=')
return -1;//栈顶和当前字符消去
return 0;//当前字符入栈
}
if(c1=='(')
{
if(c2==')')
return -1;//栈顶和当前字符消去
return 0;//当前字符入栈
}
if(c1=='+'||c1=='-')
{
if(c2=='+'||c2=='-'||c2=='='||c2==')')
return 1;//栈顶出栈
return 0;//当前字符入栈
}
if(c1=='*'||c1=='/')
{
// if(c2=='*'||c2=='/'||c2=='='||c2==')')
// return 1;//栈顶出栈
// return 0;//当前字符入栈
if(c2=='(')
return 0;
return 1;//栈顶出栈
}
return 2;//这是随便返回的
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
char str_1[9005];//原始字符
char str_2[9005];//后缀式字符
scanf("%s",str_1);
stack<char>q;//暂时存储字符栈
q.push('#');
int len_str_1=strlen(str_1);
int len_str_2=0;//后缀式字符指针
for(int i=0; i<len_str_1; i++)//中缀式转后缀式,q最后应为空
{
if(str_1[i]>='0'&&str_1[i]<='9')
{
while((str_1[i]>='0'&&str_1[i]<='9')||str_1[i]=='.')
str_2[len_str_2++]=str_1[i++];
str_2[len_str_2++]=' ';//加个空格 分开两个数字
i--;//指针处理可能有问题
}
else
{
if(Judge(q.top(),str_1[i])==-1)
q.pop();//栈顶和当前字符消去
else if(Judge(q.top(),str_1[i])==0)//当前字符入栈
q.push(str_1[i]);
else if(Judge(q.top(),str_1[i])==1)//栈顶出栈
{
while(Judge(q.top(),str_1[i])==1)
{
str_2[len_str_2++]=q.top();
str_2[len_str_2++]=' ';//加空格便于下一步处理
q.pop();
}
if(Judge(q.top(),str_1[i])==-1)
q.pop();//栈顶和当前字符消去
else if(Judge(q.top(),str_1[i])==0)
q.push(str_1[i]);//当前字符入栈
}
}
}
// if(q.empty())//中缀式转后缀式没问题
// printf("1\n");
// else
// printf("2\n");
// for(int i=0; i<len_str_2; i++)
// printf("%c",str_2[i]);
// printf("\n");//检测后缀式是否正确
stack<double>num;//装入数字
for(int i=0; i<len_str_2; i++)
{
if(str_2[i]>='0'&&str_2[i]<='9')//数字存入num栈
{
double num_1=0.0;//整数部分
double num_2=0.0;//小数部分
while(str_2[i]>='0'&&str_2[i]<='9')//小数点前的整数部分
num_1=num_1*10.0+str_2[i++]-'0';
if(str_2[i]=='.')//如果有小数
{
//小数部分需要另行处理
int flag=1;
i++;
while(str_2[i]>='0'&&str_2[i]<='9')
{
num_2=num_2+(str_2[i]-'0')*pow(0.1,flag);
flag++;
i++;
}
//这里是个大坑点,浮点数精度损失
// printf("%.2lf\n",num_2);//输出小数部分
}
num.push(num_1+num_2);
}
else if(str_2[i]!=' ')//不是空格那就可以运算了
{
if(str_2[i]=='+')
{
double num_1=num.top();
num.pop();
double num_2=num.top();
num.pop();
num.push(num_1+num_2);
}
else if(str_2[i]=='-')
{
double num_1=num.top();
num.pop();
double num_2=num.top();
num.pop();
num.push(num_2-num_1);//注意相减顺序
}
else if(str_2[i]=='*')
{
double num_1=num.top();
num.pop();
double num_2=num.top();
num.pop();
num.push(num_2*num_1);
}
else if(str_2[i]=='/')
{
double num_1=num.top();
num.pop();
double num_2=num.top();
num.pop();
num.push((num_2*1.0)/(num_1*1.0));//注意相除顺序
}
}
}
printf("%.2lf\n",num.top());
}
return 0;
}
给出两组后台测试数据,后台还有个很长的就不给出了,这俩能过基本就AC
输入
2
(1+2)*5.156/54*4.154/47852*41463=
((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154=
输出
1.03
-17.17
其实后台最长的测试输入是:
(((1+2)5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174)*5+65.54-0.54+((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-216/174)*5+65.54-0.54)(((1+2)5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174)*5+65.54-0.54)/(((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174))((((1+2)5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174)*5+65.54-0.54+((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-216/174)*5+65.54-0.54)(((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174)*5+65.54-0.54)/(((1+2)*5.156/54+4.154)/47852*41463-56*78/32*0.154*152/(784+574-256/174)))/1875/56=
输出自己算吧。。