【每日算法】AB6 表达式求值(基于逆波兰表达式)

题目

描述

请写一个整数计算器,支持加减乘三种运算和括号。
数据范围:1000≤∣s∣≤100,保证计算结果始终在整型范围内
要求:空间复杂度: O(n)O(n),时间复杂度 O(n)O(n)

示例1

输入:“1+2”
返回值:3

示例2

输入:“(2*(3-4))*5”
返回值:-10

示例3

输入:“3+234-1”
返回值:26

代码


/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 返回表达式的值
 * @param s string字符串 待计算的表达式
 * @return int整型
 */

#include <string.h>
#include <math.h>

int priority(char a) {
    if (a == '*') {
        return 2;
    } else if (a == '+' || a == '-') {
        return 1;
    }
    return 0;
}

bool isnum(char a) {
    if (a >= 48 && a <= 57)
        return true;
    return false;
}

int solve(char* s ) {
    int exp_len = strlen(s); // 表达式长度

    char final[exp_len][4]; // 存放生成的后缀表达式
    int final_p = 0; // 后缀表达式的指针

    char sign[exp_len / 2]; // 运算符栈
    int sign_p = 0;
    // step 1:转化成逆波兰表达式
    for (int i = 0; i < exp_len;) {
        if (isnum(s[i])) {
            int tmp[3] = {0};
            int j = 0;
            while (isnum(s[i])) {
                tmp[j] = s[i] - '0';
                i ++;
                j ++;
            }
            // printf("%d\n",int(pow(2, 3)));
            int res = pow(10, j - 1) * tmp[0] + pow(10, j - 2) * tmp[1] + tmp[2];
            sprintf(final[final_p ++], "%d", res);
            // 加上下面这句会输出乱码,不知道为什么
            // final[final_p ++][j] = '\0';
            continue;
        }
        // case 1
        else if (sign_p  == 0 && priority(s[i]) > 0) {
            sign[sign_p ++] = s[i];
            printf("add sign:%c\n", sign[sign_p - 1]);
        }
        // case 4
        else if (s[i] == '(') {
            sign[sign_p ++] = s[i];
            printf("add sign:%c\n", sign[sign_p - 1]);
        }
        // case 5
        else if (s[i] == ')') {
            while (sign[sign_p - 1] != '(') {
                final[final_p ++][0] = sign[--sign_p];
                final[final_p - 1][1] = '\0';
                printf("out sign and add final:%s\n", final[final_p - 1]);
            }
            final[final_p ++][0] = sign[--sign_p];
            final[final_p - 1][1] = '\0';
        }
        // case 2
        else if (priority(s[i]) >= priority(sign[sign_p - 1])) {
            sign[sign_p ++] = s[i];
            printf("add sign:%c\n", sign[sign_p - 1]);
        }
        // case 3
        else if (priority(s[i]) < priority(sign[sign_p - 1])) {
            printf("%c:%d < %c:%d\n", s[i], priority(s[i]), sign[sign_p - 1],
                   priority(sign[sign_p - 1]));
            while (sign_p != 0 && sign[sign_p - 1] != '(') {
                final[final_p ++][0] = sign[--sign_p];
                final[final_p - 1][1] = '\0';
                printf("out aign and add final:%s\n", final[final_p - 1]);
            }
            sign[sign_p ++] = s[i];
        } else {
            printf("unexpected\n");
        }
        i ++;
        for (int i_ = 0; i_ < sign_p; i_ ++) {
            printf("%c", sign[i_]);
        }
        printf("\n");
    }
    while (sign_p != 0) {
        final[final_p ++][0] = sign[--sign_p];
        final[final_p - 1][1] = '\0';
    }
    // exception : multi minus
    for (int i = final_p - 1; i >= 0; i --) {
        if (strcmp(final[i], "-") == 0) {
            printf("here\n");
            int j = i - 1;
            while (j >= 0 && strcmp(final[j], "-") == 0) {
                strcpy(final[j], "+");
                j --;
            }
        }
    }

    for (int i = 0; i < final_p; i ++) {
        printf("%s ", final[i]);
    }
    printf("\n\n");

    // step 2:逆波兰表达式求值
    int op[exp_len]; // 操作数栈
    int op_p = 0;
    for (int i = 0; i < final_p; i ++) {
        printf("stage2: %s\n", final[i]);
        if (strcmp(final[i], "+") == 0) {
            printf("+:final_p=%d\n", final_p);
            int op1 = op[--op_p];
            int op2 = op[--op_p];
            int tmp = op1 + op2;
            printf("stacksize:%d op1:%d op2:%d result:%d\n", op_p, op1, op2, tmp);
            printf("%d\n", tmp);
            op[op_p ++] = tmp;
        } else if (strcmp(final[i], "-") == 0) {
            printf("-\n");
            int op1 = op[--op_p];
            int op2 = op[--op_p];
            int tmp = op2 - op1;
            printf("stacksize:%d op1:%d op2:%d result:%d\n", op_p, op1, op2, tmp);
            printf("%d\n", tmp);
            op[op_p ++] = tmp;
        } else if (strcmp(final[i], "*") == 0) {
            printf("*\n");
            int op1 = op[--op_p];
            int op2 = op[--op_p];
            int tmp = op1 * op2;
            printf("stacksize:%d op1:%d op2:%d result:%d\n", op_p, op1, op2, tmp);
            printf("%d\n", tmp);
            op[op_p ++] = tmp;
        } else if (strcmp(final[i], "(") == 0 || strcmp(final[0], ")") == 0) {
            continue;
        } else {
            printf("push %s\n", final[i]);
            op[op_p ++] = atoi(final[i]);
        }
    }
    return op[op_p - 1];
}

思路

先将该中缀表达式转化为严格从左到右运算的后缀表达式(逆波兰表达式),然后按照AB4的思路写下去就好了:
【每日算法】AB5 逆波兰表达式

  1. 为什么要转化为逆波兰表达式
    逻辑提问式类似于算术表达式,对于检索而言,这种表达式并不是最优和最简洁的形式,需要进行必要的转换。——百度百科
  2. 将中缀表达式转化为后缀表达式的方法
    准备:一个运算符栈和一个操作数队列
    流程:从左向右遍历表达式,遇到操作直接入队,遇到运算符,分为以下几种情况:
    (1)运算符栈为空:直接将运算符压进栈中
    (2)栈不为空且栈顶运算符优先级低于当前优先级:直接将运算符压进栈中
    (3)栈不为空且栈顶运算符优先级高于当前优先级:将栈中运算符依次出栈并入队,然后将当前运算符压入栈中
    (4)当前运算符是左括弧:不考虑优先级,直接入栈
    (5)当前运算符是右括弧:出栈并压入队列,直到遇到左括弧(括弧不进队列)
    (6)遍历结束,出栈并入队

问题

  1. 由于括号不进队列,因此最好括号拿出来判断,而不是放在优先级里比较
  2. 关于幂次方,需要使用pow()函数(该函数返回类型是double),C中^是按位相与
  3. 乱码问题:比如定义字符数组a[4],赋值a[0] = ‘5’,直接输出该数组会有乱码,需要在末尾加上‘\0’,即a[1] = ‘\0’
  4. 第三种情况下,当遇到左括号,应该停止出栈
  5. 对于连续多个-,需要仅保留最后一个-,前面的都变成+
  6. 之前卡那么久,是因为多个-修正时,忽略了括号的作用,
    比如:2-(3-4)-5,
    直接转化:2 3 4 - 5 - -
    按照原方法修正:2 3 4 + 5 + -
    实际应该是:2 3 4 - 5 + -
    还是没有完全理解逆波兰,生成逆波兰表达式的时候保留括号,求值时忽略就好了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值