nyoj35 - 表达式求值

35-表达式求值

 

  • 内存限制:64MB 时间限制:3000ms 特判: No
  • 通过数:111 提交数:210 难度: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

被这道题卡成狗,原因竟然是……

思路:

方法一:按运算符优先级来算,开两个栈,num存数字,fu存符号

(1)'('  入栈

(2)')'  进行运算,直到'('出栈

(3)数字,进数字栈(我算数字,小数的时候除的10,定义成int了,wa了一年)

(4)符号,判断栈顶优先级,必须优先级大于栈顶才能入栈,否则运算

等于也不行,因为要遵循从左到右的原则呀

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<stack>
using namespace std;
typedef pair<char,int> P;
char s[1005];
map<char,int>pi;
stack<double>num;
stack<char>fu;

void cal(char f){
    double t1=num.top();num.pop();
    double t2=num.top();num.pop();
    if(f=='+'){
        num.push(t1+t2);
    }
    if(f=='-'){
        num.push(t2-t1);
    }
    if(f=='*'){
        num.push(t1*t2);
    }
    if(f=='/'){
        num.push(t2/t1);
    }
}

int main(){
    int t;
    pi.insert(P('(',0));
    pi.insert(P('+',1));
    pi.insert(P('-',1));
    pi.insert(P('*',2));
    pi.insert(P('/',2));
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        int len=strlen(s);
        for(int i=0;i<len-1;){//左括号直接入栈
            if(s[i]=='('){
                fu.push(s[i]);
                i++;
            }
            else if(s[i]>='0'&&s[i]<='9'||s[i]=='.'){//数字求值,入栈
                double n=0;
                int flag=0;
                double q=10;
                while(s[i]>='0'&&s[i]<='9'||s[i]=='.'&&i<len-1){
                    if(s[i]=='.'){
                        flag=1;
                        i++;
                        continue;
                    }
                    if(!flag){
                        n=n*10+s[i]-'0';
                    }
                    else{
                        n=n+(s[i]-'0')/q;
                        q*=10;
                    }
                    i++;
                }
                num.push(n);
            }
            else if(s[i]==')'){//右括号,计算
                char f=fu.top();
                while(f!='('){
                    cal(f);
                    fu.pop();
                    f=fu.top();
                }
                fu.pop();
                i++;
            }
            else{//运算符号
                if(fu.empty()){
                    fu.push(s[i]);
                }
                else{
                    char f=fu.top();
                    if(pi[f]<pi[s[i]]){//符号优先级大于等于栈顶符号优先级
                        fu.push(s[i]);
                    }
                    else{//优先级小,计算
                        while(pi[f]>=pi[s[i]]){
                            cal(f);
                            fu.pop();
                            if(fu.size()==0)break;
                            f=fu.top();
                        }
                        fu.push(s[i]);
                    }
                }
                i++;
            }
        }
        while(fu.size()){
            char f=fu.top();
            cal(f);
            fu.pop();
        }
        printf("%.2f\n",num.top());
        num.pop();
    }
}

方法二:来自这位老哥

也就是把字符串先转成逆波兰式,再求值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<stack>
using namespace std;
typedef pair<char,int> P;
const int N=1005;
string s1,s2;
map<char,int>pi;
void change(){
    stack<char>s;
    s.push('#');
    int i=0,len=s1.length();
    while(i<len-1){
        if(s1[i]=='('){
            s.push(s1[i++]);
        }
        else if(s1[i]==')'){
            while(s.top()!='('){
                s2+=s.top();
                s2+=' ';
                s.pop();
            }
            s.pop();
            i++;
        }
        else if(s1[i]=='+'||s1[i]=='-'||s1[i]=='*'||s1[i]=='/'){
            while(pi[s.top()]>=pi[s1[i]]){
                s2+=s.top();
                s2+=' ';
                s.pop();
            }
            s.push(s1[i]);
            i++;
        }
        else{
            while(i<len-1&&(s1[i]>='0'&&s1[i]<='9'||s1[i]=='.')){
                s2+=s1[i++];
            }
            s2+=' ';
        }
    }
    while(s.top()!='#'){
        s2+=s.top();
        s2+=' ';
        s.pop();
    }
}

double value(){
	stack<double> s;
	double x,y;
	int i = 0,len=s2.length();
	while(i<len){
		if(s2[i]==' '){
			i++;
			continue;
		}
		switch(s2[i]){
			case '+': x = s.top();s.pop();x+=s.top();s.pop();i++;break;
			case '-': x = s.top();s.pop();x=s.top()-x;s.pop();i++;break;
			case '*': x = s.top();s.pop();x*=s.top();s.pop();i++;break;
			case '/': x = s.top();s.pop();x=s.top()/x;s.pop();i++;break;
			default:{
                x=0;
                int flag=0;
                double q=10;
                while(i<len&&(s2[i]>='0'&&s2[i]<='9'||s2[i]=='.')){
                    if(s2[i]=='.'){
                        flag=1;
                        i++;
                        continue;
                    }
                    if(!flag){
                        x=x*10+s2[i]-'0';
                    }
                    else{
                        x=x+(s2[i]-'0')/q;
                        q*=10;
                    }
                    i++;
                }
			}
		}
		s.push(x);
	}
	return s.top();
}

int main(){
    int t;
    scanf("%d",&t);
    pi.insert(P('(',0));
    pi.insert(P('+',1));
    pi.insert(P('-',1));
    pi.insert(P('*',2));
    pi.insert(P('/',2));
    while(t--){
        cin>>s1;
        s2="";
        change();
        double res=value();
        printf("%.2f\n",res);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值