NYOJ-35-表达式求值

描述

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]获取一个char
int 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,等回头有空了再看吧…就这样吧。

时间: 2024-08-29 01:24:48

NYOJ-35-表达式求值的相关文章

NYOJ 35 表达式求值

一个模板了 哈哈. 这题由于已经包括了整形.浮点形了,以后也不须要特别处理了. /* 这里主要是逆波兰式的实现,使用两个stack 这里用字符串来模拟一个stack,第一步,将中缀表达式转变为后缀表达式 第二步,然后再使用一个stack,计算后缀表达式的结果.这一步非常easy出错,考虑到浮点数的问题. */ #include <iostream> #include <string> #include <cstring> #include <cstdio>

NYOJ表达式求值

表达式求值 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧. 比如输入:"1+2/4=",程序就输出1.50(结果保留两位小数) 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以"

四则运算表达式求值 OpenJ_Bailian - 4132

四则运算表达式求值 OpenJ_Bailian - 4132 题意:设计一个计算器,实现+-*/以及()的表达式运算求值. 栈的应用,这学期学数据结构,手写了栈练一下~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=10010; //最大表达式长度 4 5 template <typename T> 6 class Stack; 7 8 template <typename T> 9

数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚,所以很多需要自己揣摩.这也体现了算法和程序设计语言的特点,算法更侧重本质的描述,而任何编程语言都要照顾到实现的细节以及数据类型等语法方面的需求. 表达式求值: [编码中....] 二.头文件 迷宫求解: 1 //3_2_maze.h 2 /** 3 author:zhaoyu 4 email:[em

数据结构 表达式求值

实现表达式求值,以及表达式中括号是否匹配. 实现方法,建立两个栈,一个用来存放操作数,一个用来存放运算符.判断运算符优先级来确定什么时候出栈,利用一个数组去表示优先级 头文件代码如下: #ifndef STACK_H_INCLUDED #define STACK_H_INCLUDED #include <iostream> #include <string.h> using namespace std; template<class Type> class Stack

数据结构 -- 整数算术表达式求值 (C/C++)

数据结构题集(C语言版)--严蔚敏,吴伟民编著 设置运算符栈和运算数栈辅助分析运算符有限关系. 读入表达式的字符序列的同时完成运算符和运算数(整数)的识别处理,以及相应的运算. 在识别出运算数的同时,要将其字符序列形式转换成整数形式. 1 /** 2 Function:整数算术表达式求值 3 Date:2014-11-10 4 Author:JackDawson 5 Compiler:gcc version 4.8.1 6 */ 7 #include <iostream> 8 #include

表达式求值_栈

问题 C: 表达式求值 时间限制: 3 Sec  内存限制: 128 MB提交: 1  解决: 1[提交][状态][讨论版] 题目描述 ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧.比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数) 输入 第一行输入一个整数n,共有n组测试数据(n<10).每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每

hdu 4192(表达式求值)

题意:给一个表达式当中有一些变量,然后告诉你一些数字你可以任意排列,问能不能求出要求的结果. 思路:由于变量数目较小所以直接全排列枚举即可,然后用栈处理表达式. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last modified : 2014-06-28 21:50 5

【栈的应用】四则运算表达式求值

1. 后缀表达式计算结果 (1) 规则 从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,运算结果进栈,一直到最终获得结果. (2) 示例 后缀表达式:9 3 1 - 3 * + 10 2 / + 初始化一个空栈.此栈用来对要运算的数字进出使用: 后缀表达式中前三个都是数字,所以9.3.1依次进栈: 接下来是"-",所以将栈中的1出栈作为减数,3出栈作为背减数,并运算3-1得到2,再将2进栈: 接着是数字3进栈: 后面是"*&quo

表达式求值(数据结构书上栈的应用之一)

主要内容:表达式求值,提交nyoj通过... 思路:主要就是一个开两个栈,然后一个操作符栈,一个操作数栈.. 我的代码如下(比较简洁): /***** Author Gery ******/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<cmath&