NYOJ-35-表达式求值

来源:互联网 发布:mac high sierra好吗 编辑:程序博客网 时间:2024/04/28 11:58

描述
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

题目比较容易理解,就是实现四则运算。
说到四则运算,不得不提到逆波兰表示法,也就是后缀表示法。这种表示法不需要括号,对于9 + (3 - 1) x 3 + 10 ÷ 2用后缀表示法的样子则是:9 3 1 - 3 * + 10 2 / +。之所以叫后缀的原因是,所有的运算符号都是要在运算数字的后边出现,那么很容易的想到,我们平时写的式子,也就是第一个式子,是中缀表示法。

中缀表达式转后缀表达式规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级低于栈顶符号(乘除优先于加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止,这里我们需要一个栈来实现,用于符号的进栈出栈。

9 + (3 - 1) x 3 + 10 ÷ 2(中缀表达式) >>> 9 3 1 - 3 * + 10 2 / +(后缀表达式)

后缀表达式使用规则:从左到右遍历后缀表达式的每一个数字和符号,遇到是数字就进栈,遇到是符号,就当处于栈顶的两个数字出栈进行运算,运算结果进栈,一直到最终获得结果。

这里存在两个过程,
1.将中缀表达式转化为后缀表达式(栈用来进出运算符号)。
2.将后缀表达式进行运算得到结果(栈用来进出运算的数字)。

代码如下:

/*不知道为啥一直WA,可是我试了很多数据都可以的,哎,头疼死了。暂且记下,来日再战,我需要静静。后边的两个代码均是AC代码。*/#include <stdio.h>#include <string.h>#include <stdlib.h>#define INF 10000000#define ADD INF + 1 //+#define SUB INF + 2 //-#define MUL INF + 3 //x#define DIV INF + 4 //÷char str[1005];     //原公式int len;            //公式长度char symbol[1000];   //运算符号栈float suffix[1005]; //后缀式float answer[1000];  //运算栈//从s[*pc]开始获取一个浮点数int StrToInt(char s[], int * pc, float *pout){    char buf[100];    int i = 0;    if(s[*pc]<'0' || s[*pc]>'9')        return 1;    else    {        while((s[*pc] >= '0' && s[*pc] <= '9') || s[*pc] == '.')        {            buf[i] = s[*pc];            (*pc)++;            i++;        }        buf[i] = '\0';        *pout = (float)atof(buf);        return 0;    }}void swi(int *key, char sym){    switch (sym)    {        case '+':            suffix[(*key)++] = ADD;            break;        case '-':            suffix[(*key)++] = SUB;            break;        case '*':            suffix[(*key)++] = MUL;            break;        case '/':            suffix[(*key)++] = DIV;            break;    }}void perform(int suf, int *_key){    float a = answer[(*_key)--];    float b = answer[(*_key)];    float c;    switch (suf)    {        case (INF + 1):            c = a + b;            break;        case (INF + 2):            c = b - a;            break;        case (INF + 3):            c = a * b;            break;        default:            c = b / a;            break;    }    answer[*_key] = c;//    printf("%.2f\n", answer[*_key]);    return ;}int main(){    int T;    scanf("%d", &T);    while(T--)    {        scanf("%s", str);        len = (int)strlen(str) - 1;        int key = 0;        int top = -1;        float pout;        //中缀式转后缀式        for (int i = 0; i < len; )        {            if (!StrToInt(str, &i, &pout))            {                suffix[key++] = pout;            }            else if (top != -1 && str[i] == ')')            {                while (symbol[top] != '(')                {                    swi(&key, symbol[top--]);                }                i++;                top--;            }            else if (top != -1 && (str[i] == '+' || str[i] == '-') && (symbol[top] == '*' || symbol[top] == '/'))            {                while (symbol[top] != '(' && top >= 0)                {                    swi(&key, symbol[top--]);                }                symbol[++top] = str[i++];            }            else if (top != -1 && (str[i] == '*' || str[i] == '/') && (symbol[top] == '*' || symbol[top] == '/'))            {                swi(&key, symbol[top]);                symbol[top] = str[i++];            }            else            {                symbol[++top] = str[i++];            }        }        while (top >= 0)        {            swi(&key, symbol[top--]);        }//        for (int i = 0; i < key; i++)//        {//            printf("%f  ", suffix[i]);//        }//        printf("\n");        //后缀式运算        int _key = -1;        for (int i = 0; i < key; i++)        {            if (suffix[i] < INF)            {                answer[++_key] = suffix[i];//                printf("%.2f\n", answer[_key]);            }            else            {                perform((int)suffix[i], &_key);            }        }        printf("%.2f\n", answer[0]);    }    return 0;}

另外还有两种方法,第一种是将字符和数据分别入两个栈,然后根据优先级的比较,对数据栈顶的两个元素进行出栈操作然后进栈。

#include<stdio.h>#include<stdlib.h>//数据栈typedef struct DA{    float data[1000];    int pop;} SDA;//运算符栈typedef struct OP{    char op[1000];    int pop;} SOP;//初始化数据栈int InitSDA(SDA * p){    p->pop = 0;    return 0;}//初始化运算符栈int InitSOP(SOP * p){    p->pop = 0;    (p->op[p->pop]) = '=';    (p->pop)++;    return 0;}//数据入栈int PushSDA(SDA * p, float d){    if(p->pop < 1000)    {        p->data[p->pop] = d;        (p->pop)++;        return 0;    }    else        return 1;   //栈满}//运算符入栈int PushSOP(SOP * p, char c){    if(p->pop < 1000)    {        p->op[p->pop] = c;        (p->pop)++;        return 0;    }    else        return 1;   //栈满}//数据出栈int PopSDA(SDA * p, float * d){    (p->pop)--;    if(p->pop >= 0)    {        *d = p->data[p->pop];        return 0;    }    else        return 1;}//运算符出栈int PopSOP(SOP * p, char * c){    (p->pop)--;    if(p->pop >= 0)    {        *c = p->op[p->pop];        return 0;    }    else        return 1;}//从s[*pc]开始获取一个浮点数int StrToInt(char s[], int * pc, float *pout){    char buf[100];    int i = 0;    if(s[*pc]<'0' || s[*pc]>'9')        return 1;    else    {        while((s[*pc] >= '0' && s[*pc] <= '9') || s[*pc] == '.')        {            buf[i] = s[*pc];            (*pc)++;            i++;        }        buf[i] = '\0';        *pout = (float)atof(buf);        return 0;    }}//从s[*pc]获取一个charint StrToChar(char s[], int *pc, char *pout){    if('+'==s[*pc] || '-'==s[*pc] || '*'==s[*pc] || '/'==s[*pc] || '('==s[*pc] || ')'==s[*pc])    {        *pout = s[*pc];        (*pc)++;        return 0;    }    else        return 1;}//获取优先级char GetPri(char c1, char c2){    char f[7][7] = {'>', '>', '<', '<', '<', '>', '>',        '>', '>', '<', '<', '<', '>', '>',        '>', '>', '>', '>', '<', '>', '>',        '>', '>', '>', '>', '<', '>', '>',        '<', '<', '<', '<', '<', '=', '\0',        '>', '>', '>', '>', '\0', '>', '>',        '<', '<', '<', '<', '<', '\0', '=',};    int i=0, j=0;    switch(c1)    {        case '+': i = 0; break;        case '-': i = 1; break;        case '*': i = 2; break;        case '/': i = 3; break;        case '(': i = 4; break;        case ')': i = 5; break;        case '=': i = 6; break;    }    switch(c2)    {        case '+': j = 0; break;        case '-': j = 1; break;        case '*': j = 2; break;        case '/': j = 3; break;        case '(': j = 4; break;        case ')': j = 5; break;        case '=': j = 6; break;    }    return f[i][j];}//计算表达式float Operate(float a, char op, float b){    switch(op)    {        case '+': return a + b;        case '-': return a - b;        case '*': return a * b;        case '/': return a / b;        default: return 0;    }}int main(void){    char s[10][1000];    int c = 0;    float bufda;    char bufop;    float a, b;    SDA sda;    SOP sop;    int n;    int i;    scanf("%d", &n);    for(i = 0; i < n; i++)        scanf("%s", s[i]);    for(i = 0; i < n; i++)    {        c = 0;        InitSDA(&sda);  //初始化数据栈        InitSOP(&sop);  //初始化符号栈        while(s[i][c] != '=' || sop.op[sop.pop - 1] != '=') //  计算未完成        {            if(0 == StrToInt(s[i], &c, &bufda))                PushSDA(&sda, bufda);   //数据入栈            else            {                switch(GetPri(sop.op[sop.pop - 1], s[i][c]))                {                    case '<':                        if(0 == StrToChar(s[i], &c, &bufop))                            PushSOP(&sop, bufop);                        break;                    case '=':                        PopSOP(&sop, &bufop);                        c++;                        break;                    case '>':                        PopSOP(&sop, &bufop);                        PopSDA(&sda, &b);                        PopSDA(&sda, &a);                        PushSDA(&sda, Operate(a, bufop, b));                        break;                }            }        }        PopSDA(&sda, &a);        printf("%.2f\n", a);    }    return 0;}//改写成C++,并简化后如此//#include <stack>//#include <stdio.h>//#include <ctype.h>//#include <string.h>//#include <stdlib.h>////using namespace std;////int priority(char c)//{//    if(c == '=')    return 0;//    if(c == '+')    return 1;//    if(c == '-')    return 1;//    if(c == '*')    return 2;//    if(c == '/')    return 2;//    return 0;//}////void compute(stack<double>& Num,stack<char>& Op)//{//    double b = Num.top();//    Num.pop();//    double a = Num.top();//    Num.pop();//    switch(Op.top())//    {//        case '+':Num.push(a+b);break;//        case '-':Num.push(a-b);break;//        case '*':Num.push(a*b);break;//        case '/':Num.push(a/b);break;//    }//    Op.pop();//}////int main()//{//    int z;//    char str[1005];//    stack<double> Num;//    stack<char> Op;//    scanf("%d",&z);//    while(z--)//    {//        scanf("%s",str);//        int len = strlen(str);//        for(int i=0;i<len;i++)//        {//            if(isdigit(str[i]))//            {//                double n = atof(&str[i]);//                while(i<len && (isdigit(str[i]) || str[i]=='.'))//                    i++;//                i--;//                Num.push(n);//            }//            else//            {//                if(str[i] == '(')//                    Op.push(str[i]);//                else if(str[i] == ')')//                {//                    while(Op.top()!='(')//                        compute(Num,Op);//                    Op.pop();//                }//                else if(Op.empty() || priority(str[i])>priority(Op.top()))//                    Op.push(str[i]);//                else//                {//                    while(!Op.empty() && priority(str[i])<=priority(Op.top()))//                        compute(Num,Op);//                    Op.push(str[i]);//                }//            }//        }//        Op.pop();//        printf("%.2f\n",Num.top());//        Num.pop();//    }//    return 0;//}

第二种是动态规划,将一个大问题切割成些许小问题,和归并排序的思想相仿。

// AC(动态规划)#include<stdio.h>#include<string.h>int len;int fst[1005];char str[1005];double Jud(int begin, int end); /*计算并返回表达式在区间[begin end]中的值*/int main(){    int T, i;    double ans;    scanf("%d", &T);    while(T--)    {        memset(fst, 0, sizeof(fst)); /*一定要清0*/        scanf("%s", str);        len = (int)strlen(str)-1;        fst[0] = 1;        for(i = 1; i <= len - 1; i++) /*fst[i]表示优先级,fst[i]越大,说明优先级越高↓↓*/        {                           /*例如str[] -- ((1+2)*5+1)/4=*/            if(str[i - 1]== '(')    /*对应fst[] -- 12333222221110*/                fst[i] = fst[i - 1] + 1;            else if(str[i] == ')')                fst[i] = fst[i - 1] - 1;            else                fst[i] = fst[i - 1];        }        ans = Jud(0, len - 1); /*传入整个表达式,不包括=*/        printf("%.2f\n", ans);    }    return 0;}double Jud(int begin, int end){ /*规定区间[begin, end]的优先级标准为fst[begin]*/    int i;    double k;    for(i = begin; i <= end; i++) /*先从做左到右找到第一个处于指定优先级的'+'运算符*/    {        if(str[i]== '+' && fst[i] == fst[begin])        {            k = Jud(begin, i - 1) + Jud(i + 1, end); /*将其拆成两个个表达式的和*/            return k;        }    }    for(i = end; i >= begin; i--) /*如果找不到'+',再从右往左找到第一个处于指定优先级的'-'运算符*/    {        if(str[i]=='-' && fst[i] == fst[begin])        {            k = Jud(begin, i - 1) - Jud(i + 1, end);    /*将其拆成两个个表达式的差*/            return k;        }    }    for(i = begin; i <= end; i++)   /*如果还找不到,再从左往右找到第一个处于指定优先级的'*'运算符*/    {        if(str[i] == '*' && fst[i] == fst[begin])        {            k = Jud(begin, i - 1) * Jud(i + 1, end);    /*将其拆成两个个表达式的积*/            return k;        }    }    for(i = end; i >= begin; i--)   /*同上,从右往左找到第一个处于指定优先级的'/'运算符*/    {        if(str[i] == '/' && fst[i] == fst[begin])        {            k = Jud(begin, i - 1) / Jud(i + 1, end); /*将其拆成两个个表达式的商*/            return k;        }    }    if(str[begin]=='(') /*如果在这个[begin,end]区间里的指定优先级中没有任何运算符,说明此区间可能完全包含上一级*/    {        for(i = begin + 1; fst[i] >= fst[begin + 1]; i++);        k = Jud(begin + 1, i - 1);    }    else /*既然没有包含上一级,说明这个区间就只剩下一个数啦*/    {        char *p = str;        sscanf(p+begin, "%lf", &k); /*将这个数赋值给k,并返回*/    }    return k;}

理论上这三种均可以AC…可是我不知道第一种哪里出了BUG,等回头有空了再看吧…就这样吧。

0 0
原创粉丝点击