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

简介: 【每日算法】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. 为什么要转化为逆波兰表达式

逻辑提问式类似于算术表达式,对于检索而言,这种表达式并不是最优和最简洁的形式,需要进行必要的转换。——百度百科

  1. 将中缀表达式转化为后缀表达式的方法

准备:一个运算符栈和一个操作数队列
流程:从左向右遍历表达式,遇到操作直接入队,遇到运算符,分为以下几种情况:
(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 + -
还是没有完全理解逆波兰,生成逆波兰表达式的时候保留括号,求值时忽略就好了

目录
相关文章
|
2月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
72 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
6月前
|
算法
数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)
数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)
52 0
|
7月前
|
算法 Java
Java【算法分享 03】实用算法分享(拼写inStr、去掉字符串后边特定值、三者最小、计算表达式的值)不断增加中ing
Java【算法分享 03】实用算法分享(拼写inStr、去掉字符串后边特定值、三者最小、计算表达式的值)不断增加中ing
45 0
|
7月前
|
算法
计算表达式【学习算法】
计算表达式【学习算法】
46 0
|
算法
ACM算法训练【模拟栈,表达式求值】
思路 输入长度为n的字符串,例如:1+2+3*4*5 输出表达式的值,即:63 应该用什么数据结构:当然是栈。 应该先计算哪一步?实际应该先计算1+2。 “表达式求值”问题,两个核心关键点: 双栈,一个操作数栈,一个运算符栈; 运算符优先级,栈顶运算符和即将入栈的运算符的优先级比较: 如果栈顶的运算符优先级低,新运算符直接入栈 如果栈顶的运算符优先级高,先出栈计算,新运算符再入栈
97 0
ACM算法训练【模拟栈,表达式求值】
|
存储 算法 容器
精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)
精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)
|
算法
6.解析表达式算法
6.解析表达式算法
109 0
|
算法 关系型数据库 MySQL
数据结构与算法——二叉树+带你实现表达式树(附源码)
📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段,因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的 📖作者主页:king&南星 📖专栏链接:数据结构 🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​ 💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾 ———————————————— 版权声明:本文为CSDN博主「热爱编程的小K」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
数据结构与算法——二叉树+带你实现表达式树(附源码)
|
算法 程序员
Qz学算法-数据结构篇(表达式、递归)
数据结构的前缀、中缀、后缀表达式-&gt;(逆波兰表达式)和递归
143 0
|
算法 开发者
数据结构和算法—栈的计算表达式(4)|学习笔记
快速学习数据结构和算法—栈的计算表达式(4)
数据结构和算法—栈的计算表达式(4)|学习笔记