表达式求值
时间限制:
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
-
第一行输入一个整数n,共有n组测试数据(n<10)。
(一)题目链接:南阳理工23
解题思路:
中缀表达式转后缀表达式:首先将加、减、乘、除运算符进行优先级划分,括号为最高优先级,之后为乘除、再为加减,等号为最低优先级,方便利用栈将运算符利用特定规则进行转换。之后遍历字符串,如果为数字字符或者小数点运算符,则将其添加为后缀表达式,后加一个空格,方便之后sstreamstring流输入,如果是运算符字符,则将按照规则进行进栈或者出栈操作,进栈则将运算符压入栈顶,出栈操作则将运算符添加入后缀表达式,后加空格。
运算符规则:首先栈为空时将运算符进栈,之后遇到运算符时,将其与栈顶运算符比较,如果当前运算符优先级高于栈顶运算符,则将当前元素进栈;如果当前元素优先级低于栈顶元素,则不断出栈,直到栈中出现更低优先级或者栈为空,最后将该运算符进栈。特别的:如果是括号运算符,遇左括号,则进栈,如果遇到右括号,则出栈 栈中左括号及左括号以上所有的运算符,且右括号不进栈。
后缀表达式求值:通过以上步骤,可以得到后缀表达式字符串,且每个数字字符串和运算符字符用空格进行了分割,方便我们用streamstring进行操作,然后遍历后缀字符串,对于数字字符串,我们用 atof( )函数可将其转换为数字,同时进栈,如果遇到运算符,取栈顶元素进行相应运算,最后再将结果进栈,最后遇到等号运算符结束,当前栈中唯一栈顶元素即为表达式的值。
AC代码:
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<sstream>
#include<stack>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int Judge(char ch){
//运算符进行优先级划分
if(ch == '+') return 1;
if(ch == '-') return 1;
if(ch == '*') return 2;
if(ch == '/') return 2;
if(ch == '(') return 0;
if(ch == ')') return 0;
}
int main (void){
string str;
string s;
int count ;
cin>>count;
while(count--){
int i=0 ;
str.clear();
s.clear() ;
cin>>str;
stack<char>mid; //字符串栈 ,用于中缀表达式转后缀表达式
stack<double>ans;//数字栈 ,用于后缀表达式求值
while(str[i] != '=')
{
if(str[i] == '('){//判断,左括号进栈
mid.push(str[i]);
i++;
}
else if( str[i] == ')')//遇右括号则将左括号及左括号以上标识符出栈
{
while(mid.top()!='(')
{
s = s + mid.top() ;
s += ' ';
mid.pop() ;
}
mid.pop() ;
i++;
}
else if(isdigit(str[i]))//数字或小数点则直接转入后缀表达式
{
while(str[i]<='9'&&str[i]>='0' || str[i] =='.')
{
s = s + str[i];
i++;
}
s += ' ';
}
else if(str[i] == '+'||str[i] == '-'||str[i] == '*'||str[i] == '/'){
while(!mid.empty() && Judge(mid.top()) >= Judge(str[i])){
//当前运算标识符优先级低于栈顶元素,进行出栈操作
s = s + mid.top();
s = s + ' ';
mid.pop();
}
mid.push(str[i]);//将当前运算符进栈
i++;
}
}
while(!mid.empty())//将最后剩余运算符出栈
{
s = s + mid.top() ;
s = s + ' ';
mid.pop() ;
}
string temp;
stringstream ss(s);
char a[1000];
double num;
while(ss>>temp)
{
if( isdigit(temp[0]) ){
for(i=0;i<temp.length();i++)
a[i] = temp[i];
a[i] ='\0';//最后必须赋 '\0' 否则报错
num = atof(a);
//将数字字符串转为数字
//注意atof()函数不支持string类型,支持char()
ans.push(num);//将数字进栈
}
else{// 运算符操作
double x,y;
x = ans.top();
ans.pop();
y = ans.top();
ans.pop();
//取出栈顶两位元素 ,进行相应操作
if(temp == "+") num = x + y;
if(temp == "-") num = y - x;
if(temp == "*") num = x * y;
if(temp == "/") num = y / x;
ans.push(num);//得到元素进栈
}
}
cout<< fixed <<setprecision(2)<<ans.top()<<endl;//输出两位小数;
}
}