数据结构--后缀表达式

中缀运算符即是一般常用的数学表达方式,如a+b等运算 

后缀运算符,即将操作符放在两个操作数后面的表达式。

后缀运算符算法思想:遇到操作数则将其进栈,直至遇到操作符,将栈顶附近的两个元素提出,进行运算,将运算结果进栈,与后序操作数进行计算。

下图为abc-/]de*+(对应中缀表达式为a/(b-c)+d*e)的计算过程,其中a=6,b=4,c=2,d=3,e=2

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

根据 逆波兰表示法,求表达式的值。

有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

注意 两个整数之间的除法只保留整数部分。

可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6


示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

由于这里是字符串数组,C语言中字符串之间的比较不能用逻辑运算符==来判断,因此遍历字符串的时候判断是否是运算符需要用到库函数strcmp

 int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

声明:int strcmp(const char *str1, const char *str2)

该函数返回值如下:

  • 如果返回值小于 0,则表示 str1 小于 str2。
  • 如果返回值大于 0,则表示 str1 大于 str2。
  • 如果返回值等于 0,则表示 str1 等于 str2。

通过strcmp函数我们就完成了对字符串元素的比较问题,接下来需要考虑字符串中数字的获取入栈问题,但是由于输入的是字符串,所以需要使用atoi函数将字符串转换为数字

 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。

声明:int atoi(const char *str)

返回值:

该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。

 代码实现:

int evalRPN(char ** tokens, int tokensSize)
{
    int *stack = malloc(sizeof(int) * tokensSize);
    int top = -1;
    for (int i = 0; i < tokensSize; i++) {
        if ((strcmp(tokens[i], "+") == 0) || (strcmp(tokens[i], "-") == 0) || (strcmp(tokens[i], "*") == 0) || (strcmp(tokens[i], "/") == 0)) {
            int num2 = stack[top--];
            int num1 = stack[top--];
            if (strcmp(tokens[i], "+") == 0)
                stack[++top] = num1 + num2;
            if (strcmp(tokens[i], "-") == 0)
                stack[++top] = num1 - num2;
            if (strcmp(tokens[i], "*") == 0)
                stack[++top] = num1 * num2;
            if (strcmp(tokens[i], "/") == 0)
                stack[++top] = num1 / num2;
        } else {
            stack[++top] = atoi(tokens[i]);
        }
    }
    return stack[top];
}

 如果采用上图所示的代码进行调试,那么在一些特定的案例会报错

例如:当输入为["-128","-128","*","-128","*","-128","*","8","*","-1","*"]时

由报错可以得知,在第16行也就是乘法处发生了报错。

 在32位和64位机器中,int占32位,取值范围为-2147483648~2147483647(-2^{31} \sim 2^{31}-1

-128*-128*-128*-128*8*-1=-2,147,483,648

此时由于int类型的数据范围限制,会导致数据过大越界问题,此时采用强制类型转换,将其转换为long类型

int evalRPN(char ** tokens, int tokensSize)
{
    int *stack = malloc(sizeof(int) * tokensSize);
    int top = -1;
    for (int i = 0; i < tokensSize; i++) {
        if ((strcmp(tokens[i], "+") == 0) || (strcmp(tokens[i], "-") == 0) || (strcmp(tokens[i], "*") == 0) || (strcmp(tokens[i], "/") == 0)) {
            int num2 = stack[top--];
            int num1 = stack[top--];
            if (strcmp(tokens[i], "+") == 0)
                stack[++top] = num1 + num2;
            if (strcmp(tokens[i], "-") == 0)
                stack[++top] = num1 - num2;
            if (strcmp(tokens[i], "*") == 0)
                stack[++top] = (long)num1 * (long)num2;
            if (strcmp(tokens[i], "/") == 0)
                stack[++top] = num1 / num2;
        } else {
            stack[++top] = atoi(tokens[i]);
        }
    }
    return stack[top];
}

C++实现方法:

#include<stack>
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> s1;
        for(auto& str:tokens)
        {
            if(str!="+"&&str!="-"&&
                str!="/"&&str!="*")
            {
            s1.push(stoi(str));
            }
            else
            {
            int x1=s1.top();
            s1.pop();
            int x2=s1.top();
            s1.pop();
                switch(str[0])
                {
                 case '+':
                        s1.push(x2+x1);
                        break;
                 case '-':
                        s1.push(x2-x1);
                        break;
                 case '*':
                        s1.push(x2*x1);
                        break;
                 case '/':
                        s1.push(x2/x1);
                        break;
                }
            }
        }
        return s1.top();
    }
};

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值