【算法设计】深入理解波兰表达式与逆波兰表达式

news2024/9/22 13:27:37

在这里插入图片描述

文章目录

      • 介绍
        • 1. 波兰表达式(Prefix Notation)
        • 2. 逆波兰表达式(Postfix Notation)
        • 3. 比较与优劣
        • 4. 简单示例
        • 5. 实例演示
        • 6. 应用场景和案例
        • 7. 中缀表达式转后缀表达式
        • 8. 结论

更多相关内容可查看

应用场景:Excel自定义公式,通过逆波兰表达式是一种不错的规则选择,方便后端读取以及管理

介绍

在计算机科学与数学领域中,波兰表达式(Prefix Notation)和逆波兰表达式(Postfix Notation)是两种重要的表达式形式,它们在编程语言、计算器设计以及算法实现中有着广泛的应用。本文将详细探讨这两种表达式的定义、优势以及实际应用。

1. 波兰表达式(Prefix Notation)

波兰表达式,又称前缀表达式,是一种把运算符前置的算术表达式表示方法。在波兰表达式中,运算符位于它们所操作的数之前。例如,普通中缀表达式 2 + 3 在波兰表达式中表示为 + 2 3。这种形式消除了操作符优先级和括号的需要,通过固定的顺序来明确操作顺序。


2. 逆波兰表达式(Postfix Notation)

逆波兰表达式,又称后缀表达式,是一种把运算符置于它们所操作的数之后的算术表达式表示方法。在逆波兰表达式中,操作数先出现,后面是进行操作的运算符。例如,普通中缀表达式 2 + 3 在逆波兰表达式中表示为 2 3 +。这种形式通过顺序的结构避免了括号的使用,并且非常适合计算机的解析和计算。


3. 比较与优劣
  • 波兰表达式的优势:

    • 无需括号: 波兰表达式不需要使用括号来标识优先级,因为操作符的顺序是固定的。
    • 便于计算机解析: 波兰表达式的结构更加简单和直观,使得计算机能够轻松地解析和计算,无需进行中缀表达式到后缀表达式的转换。
  • 逆波兰表达式的优势:

    • 避免优先级问题: 逆波兰表达式直接按照操作顺序排列,避免了运算符优先级的混淆。
    • 简化计算机操作: 逆波兰表达式更加贴近计算机的工作方式,可以直接通过栈结构进行计算,实现更高效的运算。

4. 简单示例
中缀表达式 : ( a + b ) * c + d - ( e + g ) * h

前缀表达式 : 

1(( a + b ) * c + d ) - (( e + g ) * h )  // 变成 2 个表达式

2- r s  // 记 r = ( a + b ) * c + d   s = ( e + g ) * h 

3、 对于 r ,同样添加圆括号,变成 2 个子表单式  ( ( a + b ) * c ) + d   

    3.1  + ( a + b ) * c d
    
    3.2  + * ( a + b ) c d
    
    3.3  + * +  a b c d
    
4、 对于 s , ( e + g ) * h 

    4.1  * ( e + g ) h
    
    4.2  * + e g h
    
5、 最终结果 - + * + a b c d * + e g h


后缀表达式 :  a b + c * d + e g + h * -  ( 后缀表达式的推到过程与前缀表达式推导类似,只不过运算符已到括号后方)

5. 实例演示

让我们通过一个简单的例子来比较中缀、波兰和逆波兰表达式的区别:

  • 中缀表达式: (5 + 3) * 6
  • 波兰表达式: * + 5 3 6
  • 逆波兰表达式: 5 3 + 6 *

可以看到,通过波兰和逆波兰表达式,我们可以明确地知道运算符的顺序,而无需依赖括号来表达优先级,这使得表达式更加简洁和易于理解。

6. 应用场景和案例

计算器设计

在计算器设计中,波兰表达式和逆波兰表达式被广泛应用,因为它们能够简化表达式的解析和计算,同时避免了操作符优先级和括号的复杂处理。

  • 案例:
    • 计算器输入处理: 当用户输入一个数学表达式时,计算器需要将中缀表达式转换为逆波兰表达式,然后通过栈结构来计算结果。这种方法可以直接利用栈来处理运算符和操作数,从而更加高效地完成计算任务。

编程语言解析

在某些编程语言中,特别是功能型编程语言或堆栈语言,逆波兰表达式作为主要的表达式形式,用于简化语法解析和执行。

  • 案例:
    • Forth语言: Forth语言是一种堆栈式语言,它使用逆波兰表达式作为主要的语法形式。例如,执行一个操作时,先将操作数入栈,然后执行相应的操作符,这样避免了复杂的语法解析和操作符优先级问题。

数学与算法

在数学和算法领域,波兰表达式和逆波兰表达式常用于表达复杂的运算式和算法,特别是与树形算法和逻辑运算相关的应用。

  • 案例:
    • 表达式求值: 对于复杂的数学表达式或算法,波兰表达式和逆波兰表达式可以简化计算机程序的编写和执行过程。例如,对于逻辑运算或复杂的数学计算,使用逆波兰表达式可以提高程序的性能和可读性。

数据结构与算法实现

在数据结构和算法实现中,逆波兰表达式常用于表达算法的执行顺序,特别是涉及到栈操作和后缀表达式求值的情况下。

  • 案例:
    • 后缀表达式求值: 后缀表达式(逆波兰表达式)的求值可以通过简单的栈操作来实现,这种方法被广泛用于计算机科学的教学和算法设计中,如编写一个计算器程序或实现一个简单的计算机虚拟机。

实际应用举例

  • 医学图像处理: 在医学图像处理中,处理复杂的算法和表达式时,波兰表达式和逆波兰表达式可以用于简化算法的实现和优化计算的过程。
  • 网络路由算法: 在网络路由算法中,可能涉及复杂的路径选择和算法计算,逆波兰表达式的使用可以帮助简化这些计算的逻辑和流程。

7. 中缀表达式转后缀表达式

转换中缀表达式为后缀表达式(逆波兰表达式)并计算结果的过程可以分为两步:首先是将中缀表达式转换为后缀表达式,然后是对后缀表达式进行计算。下面是一个Java实现的示例代码:

import java.util.*;

public class InfixToPostfixEvaluator {

    // 操作符优先级映射
    private static final Map<Character, Integer> precedenceMap = Map.of(
        '+', 1,
        '-', 1,
        '*', 2,
        '/', 2,
        '^', 3
    );

    // 检查字符是否为操作符
    private static boolean isOperator(char ch) {
        return precedenceMap.containsKey(ch);
    }

    // 比较操作符的优先级
    private static boolean precedenceLessOrEqual(char op1, char op2) {
        return precedenceMap.getOrDefault(op1, 0) <= precedenceMap.getOrDefault(op2, 0);
    }

    // 将中缀表达式转换为后缀表达式
    public static String infixToPostfix(String infix) {
        StringBuilder postfix = new StringBuilder();
        Deque<Character> stack = new ArrayDeque<>();

        for (int i = 0; i < infix.length(); i++) {
            char ch = infix.charAt(i);

            if (Character.isLetterOrDigit(ch)) {
                // 如果是字母或数字,直接添加到后缀表达式
                postfix.append(ch);
            } else if (ch == '(') {
                // 如果是左括号,入栈
                stack.push(ch);
            } else if (ch == ')') {
                // 如果是右括号,将栈顶元素弹出直到遇到左括号
                while (!stack.isEmpty() && stack.peek() != '(') {
                    postfix.append(stack.pop());
                }
                stack.pop(); // 弹出左括号 '('
            } else { // ch 是操作符
                // 弹出栈顶所有优先级大于等于当前操作符的操作符
                while (!stack.isEmpty() && stack.peek() != '(' && precedenceLessOrEqual(ch, stack.peek())) {
                    postfix.append(stack.pop());
                }
                // 当前操作符入栈
                stack.push(ch);
            }
        }

        // 弹出栈中剩余的操作符
        while (!stack.isEmpty()) {
            postfix.append(stack.pop());
        }

        return postfix.toString();
    }

    // 计算后缀表达式的值
    public static int evaluatePostfix(String postfix) {
        Deque<Integer> stack = new ArrayDeque<>();

        for (int i = 0; i < postfix.length(); i++) {
            char ch = postfix.charAt(i);

            if (Character.isDigit(ch)) {
                // 如果是数字,将其转换并压入栈中
                stack.push(ch - '0');
            } else {
                // 如果是操作符,弹出栈顶的两个操作数进行运算
                int operand2 = stack.pop();
                int operand1 = stack.pop();
                int result;

                switch (ch) {
                    case '+':
                        result = operand1 + operand2;
                        break;
                    case '-':
                        result = operand1 - operand2;
                        break;
                    case '*':
                        result = operand1 * operand2;
                        break;
                    case '/':
                        result = operand1 / operand2;
                        break;
                    default:
                        throw new IllegalArgumentException("无效的操作符: " + ch);
                }

                // 将运算结果压入栈中
                stack.push(result);
            }
        }

        return stack.pop(); // 返回表达式的结果
    }

    public static void main(String[] args) {
        String infixExpression = "3 + 4 * 2 / ( 1 - 5 ) ^ 2";
        String postfixExpression = infixToPostfix(infixExpression);
        System.out.println("后缀表达式: " + postfixExpression);

        int result = evaluatePostfix(postfixExpression);
        System.out.println("计算结果: " + result); // 输出: -3
    }
}


8. 结论

波兰表达式与逆波兰表达式作为中缀表达式的替代形式,在各自的应用场景中展示了独特的优势。它们不仅简化了数学和计算机科学领域中复杂表达式的解析与计算,而且提高了程序执行效率和代码的可读性。通过深入理解和掌握这两种表达式形式,我们能够更好地应用于实际的软件开发与算法设计中,从而提升程序的性能和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1994139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mozilla Firefox侧边栏和垂直标签在131 Nightly版本中开始试用

垂直选项卡和全新的侧边栏体验现已在Mozilla Firefox Nightly 131 中提供。这一更新备受社区期待和要求&#xff0c;我们期待看到它如何提高您的浏览效率和工作效率。如果您想体验一下这项正在进行中的工作&#xff0c;请这样操作&#xff1a; 更新到最新的Nightly版 转到设置…

LeetCode刷题笔记第49题:字母异位词分组

LeetCode刷题笔记第49题&#xff1a;字母异位词分组 题目&#xff1a; 想法&#xff1a; 遍历列表中的所有字符串&#xff0c;将字符串中字符进行排序并作为字典的键&#xff0c;并将原字符串做为值保存&#xff0c;最终输出字典的值就是最终的答案。 class Solution:def gr…

MySQL 日志表改造为分区表

文章目录 前言1. 分区表改造方法2. 操作步骤2.1 调整主键2.2 无锁变更2.3 回滚策略 3. 分区表维护3.1 创建分区3.2 删除分区3.3 分区表查询 后记 前言 业务有一张日志表&#xff0c;只需要保留 3 个月的数据&#xff0c;仅 3 月的数据就占用 80G 的存储空间&#xff0c;如果不…

二维数组指针,指针数组,指针函数

指针 操作 二维字符型数组 1、 首先理解二维数组指针 int a[3][4]; 第一步&#xff0c;确定基类型&#xff1a;上面的数组从本质上讲&#xff0c;是一维数组的数组&#xff0c;写成int[4] a[3]可以更好的理解&#xff0c;a[3]是一个一维数组&#xff0c;其数组…

【机器学习sklearn实战】岭回归、Lasso回归和弹性网络

一 sklean中模型详解 1.1 Ride regression 1.2 Lasso regression 1.3 ElasticNet 二 算法实战 2.1 导入包 import numpy as np import pandas as pd from sklearn import datasets from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.linear…

【开源分享】PHP在线客服系统网站源码 附搭建教程

在互联网时代&#xff0c;用户对于线上服务的便捷性和高效性要求越来越高。官网在线客服系统作为企业与用户之间实时沟通的工具&#xff0c;不仅能够提高用户满意度&#xff0c;还能够有效促进业务转化。然而&#xff0c;市面上的在线客服系统大多价格昂贵且功能单一&#xff0…

[论文翻译] LTAChecker:利用注意力时态网络基于 Dalvik 操作码序列的轻量级安卓恶意软件检测

LTAChecker: Lightweight Android Malware Detection Based on Dalvik Opcode Sequences using Attention Temporal Networks 摘要&#xff1a; Android 应用程序已成为黑客攻击的主要目标。安卓恶意软件检测是一项关键技术&#xff0c;对保障网络安全和阻止异常情况至关重要。…

1.redis7安装

安装&#xff1a; redis下载地址&#xff1a; Index of /releases/ 本次使用的版本为7.0.0. yum install gcc-c 下载上传到 /opt/redis 目录&#xff0c;tar -zxvf redis-7.0.0.tar.gz 解压缩 cd redis-7.0.0 执行make 执行make install. 默认会安装到 /usr/local/bi…

超融合一体机是什么意思?有什么好处

超融合一体机是什么意思&#xff1f;超融合一体机是一种集成了计算、存储和网络功能的一体化硬件设备。通过软件定义的方式&#xff0c;提供了高度集成、高可用性、高性能的数据中心解决方案。这种一体机将多个物理服务器、存储设备和网络设备整合在一个机箱内&#xff0c;通过…

轻空间成功完成陕西渭南砂石料场气膜仓项目

轻空间&#xff08;江苏&#xff09;膜结构科技有限公司凭借卓越的技术实力与丰富的项目经验&#xff0c;成功完成了陕西省渭南市砂石料场气膜仓的建设。这一项目的顺利交付&#xff0c;不仅满足了当地对高效仓储的需求&#xff0c;也为西北地区的仓储设施建设树立了标杆。 陕西…

twoPhaseEulerFoam 全解读之二(转)

twoPhaseEulerFoam 全解读之二&#xff08;转&#xff09; 本系列将对OpenFOAM-2.1.1 中的 twoPhaseEulerFoam 求解器进行完全解读&#xff0c;共分三部分&#xff1a;方程推导&#xff0c;代码解读&#xff0c;补充说明。本篇对 twoPhaseEulerFoam 中的 UEqn.H 和 pEqn.H 中的…

C# 高级数据处理:深入解析联接 Join 与 GroupJoin 操作的应用与实例演示

文章目录 一、联接概述二、Join 操作符1. Join 操作符的基本用法2. Join 操作符示例 三、GroupJoin 操作符1. GroupJoin 操作符的基本用法2. GroupJoin 操作符示例 总结 在数据处理中&#xff0c;联接&#xff08;Join&#xff09;操作是一种非常常见的需求&#xff0c;它允许我…

C语言典型例题30

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题2.7 从银行贷了一笔款d&#xff0c;准备每月还款额为p&#xff0c;月利率为r&#xff0c;计算多少个月能还清。 设d30000元&#xff0c;p6000元&#xff0c;r1%。对求得的月份取小数点后一位&#xff0c;对第二…

【深度学习与NLP】——RNN架构解析

目录 RNN架构解析 1.1 认识RNN模型 学习目标 什么是RNN模型 RNN模型的作用 RNN模型的分类 小节总结 1.2 传统RNN模型 学习目标 传统RNN的内部结构图 小节总结 RNN架构解析 1.1 认识RNN模型 学习目标 了解什么是RNN模型.了解RNN模型的作用.了解RNN模型的分类. 什么…

如何使用Jmeter对HTTP接口进行压力测试?

我们不应该仅仅局限于某一种工具&#xff0c;性能测试能使用的工具非常多&#xff0c;选择适合的就是最好的。笔者已经使用Loadrunner进行多年的项目性能测试实战经验&#xff0c;也算略有小成&#xff0c;任何性能测试&#xff08;如压力测试、负载测试、疲劳强度测试等&#…

openai gym box space configuration

题意&#xff1a;在OpenAI Gym环境中配置一个“Box”空间 问题背景&#xff1a; I need an observation space ranging from [0,inf) 我需要一个观察空间&#xff0c;其范围是从 [0, ∞)&#xff08;0到正无穷大&#xff09; Im new to openai gym, and not sure what the fo…

【算法】最短路径算法思路小结

一、基础&#xff1a;二叉树的遍历->图的遍历 提到搜索算法&#xff0c;就不得不说两个最基础的思想&#xff1a; BFS&#xff08;Breadth First Search&#xff09;广度优先搜索 DFS&#xff08;Depth First Search&#xff09;深度优先搜索 刚开始是在二叉树遍历中接触这…

为什么企业需要安装加密软件

保护敏感数据&#xff1a; 企业通常拥有大量的敏感数据&#xff0c;如客户信息、财务数据、知识产权等。这些数据如果未经保护而被泄露&#xff0c;可能会对企业造成严重的经济损失和声誉损害。加密软件能够对这些敏感数据进行加密&#xff0c;即使数据被窃取&#xff0c;也无…

AI 时代,网关更能打了?

作者&#xff1a;澄潭、望宸 网关在网络通信中扮演着诸多角色&#xff0c;包括数据转发、协议转化、负载均衡、访问控制和身份验证、安全防护、内容审核&#xff0c;以及服务和 API 颗粒度的管控等&#xff0c;因此常见的网关种类有流量网关、安全网关、微服务网关、API 网关等…