栈--逆波兰表达式求值

本文介绍了中缀表达式与逆波兰表达式,重点讲解了如何使用栈来求解逆波兰表达式的结果。通过创建一个栈来存储操作数,从左到右遍历表达式,遇到操作数则压栈,遇到运算符则取出栈顶两个操作数进行运算并把结果压栈。最后返回栈中的结果。示例代码展示了如何计算给定的逆波兰表达式数组得出最终结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

栈–逆波兰表达式求值

中缀表达式:

​ 中缀表达式就是我们平常生活中使用的表达式,例如:1+3*2,2-(1+3)等等,中缀表达式的特点是:二元运算符总是置于两个操作数中间。

​ 中缀表达式是人们最喜欢的表达式方式,因为简单,易懂。但是对于计算机来说就不是这样了,因为中缀表达式的运算顺序不具有规律性。不同的运算符具有不同的优先级,如果计算机执行中缀表达式,需要解析表达式语义,做大量的优先级相关操作

逆波兰表达式(后缀表达式)

​ 逆波兰表达式是波兰逻辑学家J・卢卡西维兹(J・ Lukasewicz)于1929年首先提出的一种表达式的表示方法,后缀表达式的特点:运算符总是放在跟它相关的操作数之后。

中缀表达式逆波兰表达式(后缀表达式)
a+bab+
a+(b-c)abc-+
a+(b-c)*dabc-d*+
a*(b-c)+dabc-*d+

需求:

​ 给定一个只包含加减乘除四种运算的逆波兰表达式的数组表示方式,求出该逆波兰表达式的结果。

分析:

1.创建一个栈对象oprands存储操作数

2.从左往右遍历逆波兰表达式,得到每一个字符串

3.判断该字符串是不是运算符,如果不是,把该该操作数压入oprands栈中

4.如果是运算符,则从oprands栈中弹出两个操作数o1,o2

5.使用该运算符计算o1和o2,得到结果result

6.把该结果压入oprands栈中

7.遍历结束后,拿出栈中最终的结果返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wJwLcjL-1626922417686)(E:\personal\Node\数据结构与算法\笔记\assets\image12.png)]

代码实现:

/**
 * 栈--逆波兰表达式
 */
public class ReversePolishNotation {
    public static void main(String[] args) {
        //中缀表达式3*(17-15)+18/6的逆波兰表达式如下 结果为9
        String[] notation = {"3", "17", "15", "-", "*", "18", "6", "/", "+"};
        int result = caculate(notation);
        System.out.println("逆波兰表达式的结果为:" + result);
    }

    /**
     * @param notaion 逆波兰表达式的数组表示方式
     * @return 逆波兰表达式的计算结果
     */
    public static int caculate(String[] notaion) {
        // 定义栈,存储操作数,
        Stack<Integer> oprands = new Stack<>();
        // 遍历逆波兰表达式,得到每一个元素
        for (int i = 0; i < notaion.length; i++) {
            String curr = notaion[i];
            Integer o1;
            Integer o2;
            Integer result;
            // 判断当前元素是否为运算符。是,则从栈中取出两个操作数进行运算后,将结果存入栈中。不是,则为操作数,存入栈中
            switch (curr) {
                case "+":
                    // 从栈中取出两个操作数,进行运算,并将结果存入栈中(注意操作数取值的先后,后取的值为,运算符左侧的操作数)
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 + o1;
                    oprands.push(result);
                    break;
                case "-":
                    // 从栈中取出两个操作数,进行运算,并将结果存入栈中(注意操作数取值的先后,后取的值为,运算符左侧的操作数)
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 - o1;
                    oprands.push(result);
                    break;
                case "*":
                    // 从栈中取出两个操作数,进行运算,并将结果存入栈中(注意操作数取值的先后,后取的值为,运算符左侧的操作数)
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 * o1;
                    oprands.push(result);
                    break;
                case "/":
                    // 从栈中取出两个操作数,进行运算,并将结果存入栈中(注意操作数取值的先后,后取的值为,运算符左侧的操作数)
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 / o1;
                    oprands.push(result);
                    break;
                default:
                    // 当前元素为运算数,直接存入栈中
                    oprands.push(Integer.parseInt(curr));
                    break;
            }
        }
        // 循环完毕,将栈准备的结果返回
        return oprands.pop();
    }
}
### 逆波兰表达式求值算法实现 逆波兰表达式是一种后缀表达式,其中运算符位于操作数之后。为了计算逆波兰表达式的值,通常采用这一数据结构来辅助完成。以下是基于 Java 实现的逆波兰表达式求值的具体方法。 #### 方法一:单实现 此方法利用单一存储中间结果和最终结果。遍历输入数组中的每一个元素,如果遇到的是数字,则将其压入中;如果是运算符,则弹出顶两个元素作为操作数,并将它们的结果重新压回中[^1]。 ```java import java.util.Stack; public int evalRPN(String[] tokens) { Stack<Integer> stack = new Stack<>(); for (String token : tokens) { if ("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token)) { int b = stack.pop(); int a = stack.pop(); switch (token) { case "+": stack.push(a + b); break; case "-": stack.push(a - b); break; case "*": stack.push(a * b); break; case "/": stack.push(a / b); // 题目假设不会存在除以零的情况 break; } } else { stack.push(Integer.parseInt(token)); } } return stack.pop(); // 中最后剩下的即为结果 } ``` #### 方法二:优化后的双实现 这种方法引入了第二个用于临时保存某些特殊情况下可能需要的操作数序列。然而,在标准问题设定下(如题目所描述),额外的一个并非必要,因此一般仅需维持一个主要的工作即可[^4]。 #### 方法三:递归方式解析树形结构 理论上讲,可以通过构建抽象语法树(AST)并对其进行递归来解决问题。不过这种方式相对复杂度较高,且不适用于本题场景下的简单线性扫描逻辑。 以上三种方法各有优劣,但对于当前问题而言,最常用也是最容易理解的方式还是第一种——使用单个来进行迭代处理。 ### 注意事项 - 对于整数除法 `/` ,应遵循题目规定只保留整数部分。 - 假设给定的逆波兰表达式始终有效,无需担心非法输入或异常情况的发生[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农村小白i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值