11.表达式求值(1)

背景:

我们的教材中已经介绍了表达式求值的算法,现在我们将该算法的功能进行扩展,要求可以处理的运算符包括:+、-、*、/、%(整数取余)、^(乘方)、(、)。

要求:

采用算符优先算法,计算的中间结果只保留整数。

输入:

第一行为整数N。表示下面有N个表达式

从第二行起的后面N行为N个由整数构成的表达式

输出:

共N行,每行为相应表达式的计算结果。

如果判断出表达式有错误,则输出:error.

如果在计算过程中出现除数为0的情况,则输出:Divide 0.

特殊情况说明:

在表达式中,如果操作数出现负数(例如-8),则要特别注意。例如:
10加-8表示为:10+-8。
10减-8表示为:10--8。

 测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1以文本方式显示
  1. 4↵
  2. 2^3↵
  3. 2^0↵
  4. 2^3^2↵
  5. 2^(3-1)^(10-8)↵
以文本方式显示
  1. 8↵
  2. 1↵
  3. 512↵
  4. 16↵
1秒64M0
测试用例 2以文本方式显示
  1. 11↵
  2. (2+8↵
  3. 2+8)↵
  4. 8/0↵
  5. 8/(8+5-13)↵
  6. 2^(2-5)↵
  7. 10-(80-30(/3*3+4↵
  8. 10-80-30)/3*3+4↵
  9. (2+8)(3+2)↵
  10. (2)3(8)↵
  11. 30(/3+3)+4↵
  12. 10(20-8)+2↵
以文本方式显示
  1. error.↵
  2. error.↵
  3. Divide 0.↵
  4. Divide 0.↵
  5. error.↵
  6. error.↵
  7. error.↵
  8. error.↵
  9. error.↵
  10. error.↵
  11. error.↵
1秒64M0
测试用例 3以文本方式显示
  1. 2↵
  2. 10(10)↵
  3. 14*10-(10)2↵
以文本方式显示
  1. error.↵
  2. error.↵
1秒64M0
测试用例 5以文本方式显示
  1. 14↵
  2. 18-32↵
  3. 18/4↵
  4. 18%3↵
  5. 10+20*4↵
  6. 10-20/4↵
  7. (18-3)*3↵
  8. 10*(10)↵
  9. (10+2)/(8-10)↵
  10. (2*3)/(5*2)↵
  11. 10-(80-30)/3*3+4↵
  12. (((2+8)*2-(2+4)/2)*2-8)*2↵
  13. (((8+2)*(4/2)))↵
  14. 10/0↵
  15. (10-80*2↵
以文本方式显示
  1. -14↵
  2. 4↵
  3. 0↵
  4. 90↵
  5. 5↵
  6. 45↵
  7. 100↵
  8. -6↵
  9. 0↵
  10. -34↵
  11. 52↵
  12. 20↵
  13. Divide 0.↵
  14. error.↵
1秒64M0

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define MAX 9999999

int figure[100];  //存入数字
char symbol[100]; //存入操作符
//下标
int topf = -1;
int tops = -1;
//一起用来定位优先顺序
char operation[9] = {'+', '-', '*', '/', '(', ')', '#', '^', '%'};
char checklist[9][9] = {
    {'>', '>', '<', '<', '<', '>', '>', '<', '<'},
    {'>', '>', '<', '<', '<', '>', '>', '<', '<'},
    {'>', '>', '>', '>', '<', '>', '>', '<', '>'},
    {'>', '>', '>', '>', '<', '>', '>', '<', '>'},
    {'<', '<', '<', '<', '<', '=', ' ', '<', '<'},
    {'>', '>', '>', '>', ' ', '>', '>', '>', '>'},
    {'<', '<', '<', '<', '<', ' ', '=', '<', '<'},
    {'>', '>', '>', '>', '<', '>', '>', '<', '>'},
    {'>', '>', '>', '>', '<', '>', '>', '<', '>'}};

int number(char *q)
{
    return (int)(*q - '0');
}

void push_figure(int q)
{
    figure[++topf] = q;
}

void push_symbol(char ch)
{
    symbol[++tops] = ch;
}

int pop_figure()
{
    return figure[topf--];
}
//取出刚刚存入的这个符号
char pop_symbol()
{
    return symbol[tops--];
}

char compare(char x, char y)
{
    int a, b; //用来定位下标输出优先顺序
    for (int i = 0; i < 9; i++)
    {
        if (operation[i] == x)
        {
            a = i;
            break;
        }
    }
    for (int i = 0; i < 9; i++)
    {
        if (operation[i] == y)
        {
            b = i;
            break;
        }
    }
    //得到优先级关系并且作为返回值
    return checklist[a][b];
}

int operate(int x, int y, char symbol)
{
    switch (symbol)
    {
    case '+':
        return x + y;
    case '-':
        return x - y;
    case '*':
        return x * y;
    case '/':
        if (y)
            return x / y;
        else
        {
            printf("Divide 0.\n");
            return MAX;
        }
    // C 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数。
    case '%':
        return (int)fmod(x, y);
    case '^':
        if (y >= 0)
            return (int)pow(x, y);
        else
        {
            printf("error.\n");
            return MAX;
        }
    default:
        printf("error.\n");
        return MAX;
    }
}

int main(int argc, char *argv[])
{
    int n;
    int flag; //数字0,( 为1,其他2
    char expression[100], *p, *negative;
    char firstnega = '0';

    // freopen("file.txt","r",stdin);
    scanf("%d", &n);

    while (n--)
    {
        flag = 2;
        memset(expression, '\0', 100);
        scanf("%s", expression);

        strcat(expression, "#");
        p = expression;
        negative = expression;

        // 第一个符号是负数号且第二个字符是数字
        // 把负数号替换为0
        //指针操作,原来的也会被修改
        if (*negative == '-' && *(negative + 1) == '(')
        { //这种情况  -(2+2)+1 直接在figure中插入一个0
            push_figure(number(&firstnega));
        }

        if (*negative == '-' && *(negative + 1) >= '0' && *(negative + 1) <= '9')
        {
            *negative = '0';
        }
        negative++;
        // 遍历每一个字符
        // 前一个字符不是数字,这个字符是“-”号
        // 就把这个字符替换为0
        for (; *negative != '\0'; negative++)
        {
            if ((*(negative - 1) < '0' || *(negative - 1) > '9') && (*negative == '-') && *(negative - 1) != ')')
            {
                *negative = '0';
            }
        }
        //在栈symbol中插入#
        push_symbol('#');
    k:
        while (*p != '#' || symbol[tops] != '#')
        {
            // 遇到数字
            if (*p >= '0' && *p <= '9')
            {
                if (flag == 0)
                {
                    //如果之前有负数的符号的话会改为0,然后0在这里作为判断标志在figure里面存入负数
                    if (figure[topf] <= 0)
                        push_figure(pop_figure() * 10 + number(p++) * (-1));
                    else
                        push_figure(pop_figure() * 10 + number(p++));
                }
                else
                    push_figure(number(p++));
                //说明已经插入过数字了,注意是一位一位的插入
                flag = 0;
            }
            //不是数字
            else
            {
                //考虑的是(+这种情况
                if (flag == 1)
                {
                    if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' || *p == '^')
                    {
                        printf("error.\n");
                        goto j;
                    }
                }
                //扫描到左括号时这种情况标记为1
                if (*p == '(')
                {
                    flag = 1;
                }
                else
                    flag = 2;

                if (tops == -1)
                {
                    printf("error.\n");
                    goto j;
                }
                else
                {
                    char ch = pop_symbol(), ans;
                    // 把现在扫描到的这个符号和刚刚存入的那个操作符进行优先级比较
                    ans = compare(ch, *p);
                    if (ans == ' ')
                    {
                        printf("error.\n");
                        goto j;
                    }
                    //优先级小,将其存入
                    else if (ans == '<')
                    {
                        push_symbol(ch); //把取出来的重新存进去
                        push_symbol(*p++);
                        goto k;
                    }
                    // 优先级相同,tops指向上一位不变动,直接扫描下一个p,待会插入时直接覆盖掉(
                    else if (ans == '=')
                    {

                        p++;
                        goto k;
                    }
                    else
                    {
                        //对x,y,ch进行运算,并将数字存进

                        int integer_x, integer_y;
                        integer_y = pop_figure();
                        integer_x = pop_figure();
                        int judge = operate(integer_x, integer_y, ch);
                        if (judge == MAX)
                            goto j;
                        else
                            push_figure(judge);
                        continue;
                    }
                    p++;
                }
            }
        }
        if (topf == 0 && tops == 0)
            printf("%d\n", figure[topf]);
        else
        {
            printf("error.\n");
        }
    // 初始化,重新开始新的算式运算
    j:
        memset(expression, '\0', 100);
        topf = -1;
        tops = -1;
    }
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值