nyoj35 表达式求值

题目说的很清楚,感觉类似于编译原理的中序表达式求值,定义两个栈,一个存放符号顺序一个存放数值。程序主要就是
1.处理数值,我采用的是一个字符一个字符的输入方式,通过bool isnum(char ch)函数判断输入字符ch是否为数字,是的话分两步走,若之前输入字符中含有小数点‘.’,那么对该字符进行小数处理,如果没有识别到小数点,则按整数部分处理。

           if(ch=='.'){
                    flag=1;
                    ch=getchar();
                    continue;
                  }
                num=ch-'0';//ascii码转换为数值
                if(!flag){
                     intnum=intnum*10+num;//整数处理
                }else{
                   decimal=decimal+num/times;//小数处理
                   times=times*10;//times初值为10
                }

在程序识别到下一字符不再是数字的时候,我们将处理好的字符压入数字栈opsign。

         if(!isnum(ch)){
                       flag=0;times=10;//初始化
                       intnum=intnum+decimal;//整数部分和小数部分之和
                       opdata.push(intnum);//压入数字栈
                       intnum=0;decimal=0;
                }   

2.符号处理。当输入的数据是符号的时候,我们需要判断数字的运算顺序,也就是符号栈中的顺序。基于本人优异的小学数学功底,算术运算的规则自然不在话下:
(1)先乘除,后加减。
(2)从左到右运算。
(3)先算括号内的,再算括号外的。
由于题目所给的测试数据均以“=”结尾,所以等号的优先级是最低的,我们把等号压入栈底,而当“(”与“)”和“=”与“=”相遇时(也就是运算完成),我们需要将他们消除,所以我们定义以上两对优先级相同。至此,我们可以得到优先关系的表,我们用二维数组表示,数值-1表示’<’关系,数值0表示‘=’关系,数值1表示’>’大于关系。数值999表示出错。该二维数组如下:

int prior[7][7]={1,1,-1,-1,-1,1,1,
                 1,1,-1,-1,-1,1,1,
                 1,1,1,1,-1,1,1,
                 1,1,1,1,-1,1,1,
                 -1,-1,-1,-1,-1,0,999,
                 1,1,1,1,999,1,1,
                 -1,-1,-1,-1,-1,999,0};/*优先级表格{0=>+,1=>-,2=>*,3=>/,4=>(, 5=>),6=>= }*/ 

3.有了优先级表格后,就可以对输入表达式进行匹配了。
首先我们需要将标志匹配完成的“=”压入符号栈中,后逐个读取输入字符,数字就按1所说处理后压入数字栈,若是符号则有以下三个处理规则:
1.当栈顶元素比输入字符优先级低时,即prior[栈顶元素][输入符号]==-1时,将输入符号压入栈中。
2.当括号匹配时,将“(”弹出并接收下一字符。即prior[栈顶元素][输入符号]==0时.
3.当栈顶元素比输入字符优先级高时,即prior[栈顶元素][输入符号]==1时,将运算符op退栈存入变量中,从数据栈先后退出a,b两个数值,计算表达式:b op a = ans 的值,将结果ans压入数据栈。
4.当字符栈元素和输入元素均为“=” 时跳出循环,此时,数据栈顶元素就是要求的结果。
附上完整ac代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
/*
一些测试数据 
7
3*(7-2)=
235.2365+25498.215=
1.01-2=
(1+2)/4=
((1+2)/4+(3-5))*2=
1.000+2/4=
((1+2)*5+1)/4=
*/
int n;
int prior[7][7]={1,1,-1,-1,-1,1,1,
                 1,1,-1,-1,-1,1,1,
                 1,1,1,1,-1,1,1,
                 1,1,1,1,-1,1,1,
                 -1,-1,-1,-1,-1,0,999,
                 1,1,1,1,999,1,1,
                 -1,-1,-1,-1,-1,999,999};/*优先级表格{0=>+,1=>-,2=>*,3=>/,4=>(,
                 5=>),6=>= }*/ 
bool isnum(char ch){
    if(ch!='='&&ch!='+'&&ch!='-'&&ch!='*'&&ch!='/'&&ch!='('&&ch!=')')return true;
    return false;
}
int table(char ch){
    switch(ch){
        case '+':return 0;
        case '-':return 1;
        case '*':return 2;
        case '/':return 3;
        case '(':return 4;
        case ')':return 5;
        case '=':return 6;
    }
}
double oprea(double a,double b,char op){
    switch(op){
        case '+':return a+b;
        case '-':return a-b;
        case '*':return a*b;
        case '/':return a/b;
    }
}            
int main(){
    scanf("%d",&n);
    getchar();
    while(n--){
        char ch;
        double intnum=0;
        double decimal=0;
        bool flag=0;//判断是整数输入还是小数输入 
        double times = 10;
        double num=0; 
        stack<double>opdata;//操作数栈 
        stack<char>opsign;//操作符栈 
        opsign.push('=');
        ch=getchar();
        while(ch!='='||opsign.top()!='='){
              if(isnum(ch)){
                  if(ch=='.'){
                    flag=1;
                    ch=getchar();
                    continue;
                  }
                num=ch-'0';
                if(!flag){
                     intnum=intnum*10+num;
                }else{
                   decimal=decimal+num/times;
                   times=times*10;
                }
                ch=getchar();
                if(!isnum(ch)){
                       flag=0;times=10;
                       intnum=intnum+decimal;
                       opdata.push(intnum);
                       intnum=0;decimal=0;
                }   
              }else{
                int a=table(ch);
                int b=table(opsign.top());  
                switch (prior[b][a]){
                    case -1:opsign.push(ch);
                            ch=getchar();
                            break;
                    case 0:opsign.pop();
                           ch=getchar();
                           break;
                    case 1:char sign=opsign.top();opsign.pop();
                            double beh=opdata.top();opdata.pop();    
                            double bef=opdata.top();opdata.pop(); 
                            opdata.push(oprea(bef,beh,sign));
                            break;    
                   }
            }   
          }
        printf("%.2lf\n",opdata.top());
        getchar();
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值