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

简介: 中缀表达式转后缀表达式(逆波兰式)

一. 什么是后缀表达式



例如: a + b * c + ( d * e + f ) * g , 这是日常中我们看到的简单计算表达式, 这就是一个中缀表达式.

哪什么是后缀表达式呢? 上面这个中缀表达式又该如何转换成后缀表达式呢?


  • 将中缀表达式按照运算规则加上括号
  • 将括号内的运算符号放在对应括号外面
  • 去掉所有的括号


例如上面的中缀表达式 a + b * c + ( d * e + f ) * g


  • 将中缀表达式按照运算规则加上括号
    ( ( a + ( b * c ) ) + ( ( ( d * e ) + f ) * g ) )
  • 将括号内的运算符号放在对应括号外面
    ( ( a ( b c ) * ) + ( ( ( d e ) * f ) + g ) * ) +
  • 去掉所有的括号
    a b c * + d e f + g * +
    通过上面三步转换, 就让中缀表达式转为了后缀表达式, 最终的结果就是后缀表达式, 也叫做逆波兰式


二. 逆波兰式的使用



知道了如何变为一个逆波兰式, 也就是后缀表达式, 那么 怎么实现他呢? 例如很多带计算器功能的软件中, 用户输入的都是一个中序表达式, 计算机是通过后缀表达式来计算的, 因此如何用代码实现后缀表达式就至关 重要了.


用栈来模拟实现后缀表达式的计算结果 :

  • 遍历后缀表达式中非操作符( + - * / ) 放入压栈
  • 遇到操作符则从栈顶弹出两个元素, 第一个出栈的数为右操作数, 第二个出栈的数为左操作数
  • 弹出的栈顶元素计算后重新压栈
  • 直至后缀表达式遍历完, 最后弹出栈顶的元素则为计算结果
  • 遍历后缀表达式中非操作符( + - * / ) 放入压栈

b84ed66431a98ffaab82ef9c92fe88ba.png


此时遇到的 a b c 均为非操作符, 因此全部压栈, 直至遇到第一个操作符

  • 遇到操作符则从栈顶弹出两个元素, 第一个出栈的数为右操作数, 第二个出栈的数为左操作数

8cce3a3c19fab00931f9d7cd88c56b3f.png


此时遇到了操作符 , **因此弹出栈顶元素 c 作为右操作数, 弹出第二个栈顶元素 b 作为左操作数

那么, 为什么弹出的第一个栈顶元素时右操作数, 而不是左操作数呢 ?


** 运算法则中, 加减乘除的优先级不同, 如果弹出得第一个元素为左操作数, 可能会因为运算法则的优先级, 导致最终结果错误


例如 :


计算表达式 : a + b * c , a = 1, b = 2, c = 3 , 此时无论 左操作数是 b 还是 c 对于当前表达式都不会影响结果


当 变成 a + b - c 时, a = 1, b = 2, c = 3, b - c 中左操作数如果是 c 右操作数是 b 那么 b - c 就是正数; 同样 左操作数如果是 b 右操作数如果是 c 那么 b - c 就是负数, 会影响后面的计算结果


  • 弹出的栈顶元素计算后重新压栈


7a7dc3fefb52080f3679b20866830a3a.png


将出栈后的左操作数和右操作数计算后的结果重新入栈


  • 直至后缀表达式遍历完, 最后弹出栈顶的元素则为计算结果

直至后缀表达式全部遍历完, 最后计算结果保存在栈顶中


三. LeetCode 逆波兰式练习



了解逆波兰表达式如何来的以后, 就可以上力扣去挑战一下啦

leetCode - 逆波兰表达式(点击即可跳转)


根据上面的逆波兰表达式的实现, 可以写出如下代码 :

class Solution {
    // 需要注意的是, 该题中是字符串数组
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        // 1. 遍历字符串数组判断该字符是否为操作符
        for(String s : tokens) {
            if(!isOperator(s)) {
                // 2. 如果不是操作符, 当前元素就压栈    
                stack.push(Integer.parseInt(s));
            }else {
                // 3. 如果是操作符, 弹出栈顶元素, 第一个为右操作数, 第二个为左操作数
                int num2 = stack.pop(); // num2 始终为右操作数
                int num1 = stack.pop(); // num1 始终为左操作数
                // 4. 计算完成后的结果进行压栈
                switch(s) {
                    case "+" :
                        stack.push(num1 + num2);
                        break;
                    case "-" :
                        stack.push(num1 - num2);
                        break;
                    case "*" :
                        stack.push(num1 * num2);
                        break;
                    case "/" :
                        stack.push(num1 / num2);
                        break;
                }
            }
        }
        // 5. 遍历结束后, 弹出栈顶元素即为所求结果
        return stack.pop();
    }
    // 判断是否为操作符
    private boolean isOperator(String s) {
        if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
            return true;
        }
        return false;
    }
}


逆波兰表达式学会了, 就可以根据中序表达式简单的实现一个模拟计算器的功能啦, 可以试一试

相关文章
【汉诺塔】经典递归问题(Java实现)图文并茂讲解
【汉诺塔】经典递归问题(Java实现)图文并茂讲解
|
1月前
|
缓存 安全 Windows
错误代码0x80004005解决办法分享
以下是解决Windows系统错误代码0x80004005的多种方法,综合了多个高可信度来源的建议:
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
9月前
|
机器学习/深度学习 人工智能 UED
OOTDiffusion:开源AI虚拟试衣工具,智能适配性别和体型自动调整衣物
OOTDiffusion是一款开源的AI虚拟试衣工具,能够智能适配不同性别和体型,自动调整衣物尺寸和形状,生成自然贴合的试穿效果。该工具支持半身和全身试穿模式,操作简单,适合服装电商、时尚行业从业者及AI试穿技术爱好者使用。
823 27
OOTDiffusion:开源AI虚拟试衣工具,智能适配性别和体型自动调整衣物
|
11月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
1154 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
11月前
|
算法 Java C语言
【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
1651 1
|
缓存 数据可视化 NoSQL
【异常】springboot集成@Cacheable缓存乱码的问题解决方案
【异常】springboot集成@Cacheable缓存乱码的问题解决方案
428 1
|
存储
中缀表达式转化为后缀表达式
中缀表达式转化为后缀表达式
498 0
|
存储
汉字和数字站几个字节,估算内存占用情况
该文内容讲述了字符和字节的关系:中文标点占3字节,英文字母或数字占1字节,英文标点也占1字节。1字节等于8字位,1字位是1个二进制数。此外,还介绍了存储单位的换算:1B=8b,1KB=1024B,1MB=1024KB,1GB=1024MB。其中,b代表字位,B代表字节,KB是千字节,MB是兆字节,GB是吉字节。
631 2
|
前端开发 数据可视化 UED
【Web 前端】标签上title与alt属性有什么区别?
【4月更文挑战第22天】【Web 前端】标签上title与alt属性有什么区别?