数据结构与算法-(7)---栈的应用-(3)表达式转换

news2024/11/29 16:40:25

🌈write in front🌈
🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流.
🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如需转载还请通知⚠️
📝个人主页:Aileen_0v0🧸—CSDN博客
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
📣系列专栏:Aileen_0v0🧸的数据结构与算法学习系列专栏🌸——CSDN博客
🗼我的格言:"没有罗马,那就自己创造罗马💫~"

目录

​编辑

​编辑

回顾 🧸

​编辑

中缀表达式🀄

全括号表达式与前后缀表达式的关系🎡

中缀表达式转换为前后缀形式的方法🪐

通用的中缀转后缀算法⭐

利用中缀转后缀的操作流程🪂

转成后缀表达式对应的代码🚀



 

回顾 🧸

"温故而知新"

通过思维导图回顾一下我们学了什么,我们先学了什么是线性结构,栈(Stack)是一种抽象数据类型的线性结构,栈是什么,栈的特点以及操作步骤,我们还可以通过列表去实现栈,不过不同的栈顶其对应的时间复杂度也不同,了解完栈的基础知识点后我们开始学习栈的应用,栈可以用于

(1)匹配符号(Balance Symbols),

    (2)进制转换(Decimal conversion),

    (3)表达式转换(Experssion conversion)」

(1) 和 (2) 我们已经在前面的文章写过了:不记得知识点或者对前面内容感兴趣的小伙伴可以点击👉

🔗(1)http://t.csdnimg.cn/Ypv3q

🔗(2)http://t.csdnimg.cn/OLIJW

对应专栏数据结构与算法学习系列专栏🌸🔗:http://t.csdnimg.cn/6BQDo

中缀表达式🀄

我们通常看到的表达式如:B*C , 很容易就知道是B乘以C

像  这种操作符( operator ) 介于操作数 ( operand )中间的表示法,称为 "中缀" 表示法.

But sometimes 中缀表示法会 case confusion(引起混淆),如 "A + B * C"

是A+B然后再乘以C  还是B*C然后再加A?

为了消除混淆,人们引入"优先级"的概念

规定高优先级的操作符先计算
相同优先级的操作符从左到右依次计算这样A+B*C就没有疑义是A加上 B与C的乘积
同时
引入了括号来表示强制优先级括号的优先级最高,而且在嵌套的括号中,内层的优先级更高这样(A+B)*C就是A与B的和再乘以C


全括号表达式与前后缀表达式的关系🎡

虽然人们已经习惯了这种表示法,但计算机处理最好是能明确规定所有的计算顺序,这样无需处理复杂的优先规则
于是,我们引入全括号表达式:

在所有的表达式项两边都加上括号A+B*C+D,应表示为((A+(B*C))+D)
可否将表达式中操作符的位置稍移动一下?

例如中缀表达式A+B操作符移到前面,变为"+AB"
或者将
操作符移到最后,变为“AB+
我们就得到了表达式的另外两种表示法:"
前缀"和“后缀”表示法以操作符相对于操作数的位置来定义

这样A+B*C将变为前缀的"+A*BC"后缀的"ABC*+"为了帮助理解,子表达式加了下划线

前缀和后缀表达式中,操作符的次序完全决定了运算的次序,不再有混淆

所以在很多情况下,表达式在计算机中的表示都避免使用复杂的中缀形式

让我们先看看这些前中缀和后缀表达式

中缀表达式前缀表达式后缀表达式
A + B * C + D+ + A * B C DA B C * + D +
( A + B ) * ( C + D )* + A B + C DA B + C D + *
A * B + C * D+ * A B * C DA B * C D * +
A + B + C + D+ + + A B C DA  B + C + D +

想必初看的小伙伴会觉得眼花缭乱,但是不要着急,我们接下来会一一讲解.

一定得有个算法来转换任意复杂的表达式

为了分解算法的复杂度,我们从“全括号中缀表达式入手我们看A+B*C

如果写成全括号形式:(A+(B*C)),显式表达了计算次序我们注意到每一对括号,都包舍了一组完整的操作符和操作数,让我们看看如何将其转换成前后缀表达式吧~


中缀表达式转换为前后缀形式的方法🪐

✨Summary:

        (1)将中缀表达式转换为全括号形式

        (2)将所有的操作符移动到子表达式所在的 左括号(前缀prefix) 或者 右括号(后缀postfix) 处~

              替代之,再删除所有的括号.


通用的中缀转后缀算法⭐

在中缀表达式转换为后缀形式的处理过程中,操作符比操作数要晚输出

所以在扫描到对应的第二个操作数之前,需要把操作符先保存起来


而这些暂存的操作符,由于优先级的规则还有可能要反转次序输出.

在A+B*C中,+虽然先出现,但优先级比后面这个*要低,所以它要等*处理完后,才能再处理.


这种反转特性,使得我们考虑用保存暂时未处理操作符

再看看(A+B)*C,对应的后缀形式是AB+C*
这里+的输出比*要早,主要是因为括号使得+的优先级提升,高于括号之外的*


根据上面的“全括号”表达式,后缀表达式中操作符应该出现在左括号对应的右括号位置

所以遇到左括号,要标记下,其后出现的操作符优先级提升了,一旦扫描到对应的右括号,就可以马上输出这个操作符

总结:

在从左到右扫描逐个字符扫描中缀表达式的过程中,采用一个来暂存未处理的操作符
这样,栈顶的操作符就是
最近暂存进去的,当遇到一个新的操作符,就需要跟栈顶的操作符比较下优先级,再行处理--->新符号和栈顶对比,新的高,就入栈(因为取时也先取);       新的低,就把栈顶出栈,让栈顶的先运算.

利用中缀转后缀的操作流程🪂

后面的算法描述中,约定中缀表达式是由空格隔开的一系列单词(token)构成

操作符单词包括*/+-()

操作数单词则是单字母标识符A、B、C等。

1.首先,创建空栈opstack用于暂存操作符空表postfixList用于保存后缀表达式

2.将中缀表达式转换为单词(token)列表

    A + B*C = split => ['A', '+', 'B', ' * ', 'C']

图解: 

转成后缀表达式对应的代码🚀

class Stack:#Stack---->ADT
    def __init__(self):
        self.items =[]

    def isEmpty(self):
        return self.items == []

# 满足这些属性(行为)的是栈
    def push(self,item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def peek(self):
        return self.items[len(self.items)-1]

    #
    def size(self):
        return len(self.items)

def infixToPostfix(infixexpr):
    # 记录操作符优先级
    prec = {}
    prec["*"] = 3
    prec["/"] = 3
    prec["+"] = 2
    prec["-"] = 2
    prec["("] = 1
    opStack = Stack()
    postfixList = []
    # 解析表达式到列表
    tokenList = infixexpr.split()

    for token in tokenList:
        # 操作数
        if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789":
            postfixList.append(token)
        #  (
        elif token == "(":
            opStack.push(token)
        #  )
        elif token == ")":
            topToken = opStack.pop()
            while topToken != '(':
                postfixList.append(topToken)
                topToken = opStack.pop()
        # 操作符
        else:
            while (not opStack.isEmpty()) and \
                    (prec[opStack.peek()] >= prec[token]):
                        postfixList.append(opStack.pop())
            opStack.push(token)

    while not opStack.isEmpty():
        #  操作符
        postfixList.append(opStack.pop())
        #  合成后缀表达式字符串   
    return " ".join(postfixList)
print(infixToPostfix("A + B * C "))

运行代码测试结果 :

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

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

相关文章

区块链(8):p2p去中心化之websoket服务端实现业务逻辑

1 业务逻辑 例如 peer1和peer2之间相互通信 peer1通过onopen{ write(Mesage(QUERY_LATEST))} 向peer2发送消息“我要最新的区块”。 peer2通过onMessage收到消息,通过handleMessage方法对消息进行处理。 handleMessage根据消息类型进行处理 RESPONSE_BLOCKCHAIN:返回区块链…

WSL2和ubuntu的安装过程

目录 1.WSL2的安装 2.Ubuntu的安装 3.安装完成后的打开方式 1.WSL2的安装 按下WINX键,选择Windows PowerShell (管理员) 1.1执行以下命令,该命令的作用是:启用适用于 Linux 的 Windows 子系统 dism.exe /online /enable-feature /featur…

BI神器Power Query(25)-- 使用PQ实现表格多列转换(1/3)

实例需求:原始表格包含多列属性数据,现在需要将不同属性分列展示在不同的行中,att1、att3、att5为一组,att2、att3、att6为另一组,数据如下所示。 更新表格数据 原始数据表: Col1Col2Att1Att2Att3Att4Att5Att6AAADD…

经典网络解析(四) transformer | 自注意力、多头、发展

文章目录 1 背景1.1 困境1.2 基本架构 2 嵌入层3 编码器部分3.1 自注意力层3.2 多头注意力机制3.3 LayerNorm归一化层 4 解码器5 transformer的发展6 代码 1 背景 1.1 困境 transformer可以并行训练,也是用来实现attention注意力机制 之前RNN的困境 &#xff08…

【PostgreSQL】【存储管理】表和元组的组织方式

外存管理负责处理数据库与外存介质(PostgreSQL8.4.1版本中只支持磁盘的管理操作)的交互过程。在PostgreSQL中,外存管理由SMGR(主要代码在smgr.c中)提供了对外存的统一接口。SMGR负责统管各种介质管理器,会根据上层的请求选择一个具体的介质管理器进行操作…

【最优化理论】线性规划标准模型的基本概念与性质

我们在中学阶段就遇到过线性规划问题,主要是二维的情况,而求解的方法一般是非常直观、高效的图解法。根据过往的经验,线性规划问题的最优目标值一般在可行域的顶点处取得,那么本文就对这个问题进行更深入的探讨,维度也…

找不到msvcp140.dll解决方法的5个解决方法以及msvcp140.dll丢失原因分析

msvcp140.dll 是 Microsoft Visual C 2017 Redistributable 的一部分,许多应用程序和游戏都需要这个动态链接库(DLL)才能正常运行。如果您的系统中找不到 msvcp140.dll,您可能会遇到无法打开某些应用程序或游戏的困境。小编将讨论…

运用动态内存实现通讯录(增删查改+排序)

目录 前言: 实现通讯录: 1.创建和调用菜单: 2.创建联系人信息和通讯录: 3.初始化通讯录: 4.增加联系人: 5.显示联系人: 6.删除联系人: ​编辑 7.查找联系人: ​…

nodejs+vue健身服务应用elementui

第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性:技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性: 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…

AWS Lambda Golang HelloWorld 快速入门

操作步骤 以下测试基于 WSL2 Ubuntu 22.04 环境 # 下载最新 golang wget https://golang.google.cn/dl/go1.21.1.linux-amd64.tar.gz# 解压 tar -C ~/.local/ -xzf go1.21.1.linux-amd64.tar.gz# 配置环境变量 PATH echo export PATH$PATH:~/.local/go/bin >> ~/.bashrc …

【小沐学前端】Node.js实现基于Protobuf协议的WebSocket通信

文章目录 1、简介1.1 Node1.2 WebSocket1.3 Protobuf 2、安装2.1 Node2.2 WebSocket2.2.1 nodejs-websocket2.2.2 ws 2.3 Protobuf 3、代码测试3.1 例子1:websocket(html)3.1.1 客户端:yxy_wsclient1.html3.1.2 客户端&#xff1a…

绘制动图,金星木星月亮太阳绕圆

图💫 input绘制 行星 木星 太阳 地球 金星💫 地球 月亮各自旋转 1年 角度 360.gif import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation import math import os# 设置中文字体 font_style 宋体 plt.rcParam…

11Spark

1.安装 anaconda 在官网上下载anaconda linux 后缀为.sh的安装包 运行sh ./Anaconda3-2021.05-Linux-x86_64.sh 安装过程: 输入yes后就安装完成了. 验证: 安装完成后, 退出SecureCRT 重新进来: 看到这个base开头表明安装好了. base是默认的虚拟环…

条件查询和数据查询

一、后端 1.controller层 package com.like.controller;import com.like.common.CommonDto; import com.like.entity.User; import com.like.service.UserService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import …

用于YOLO格式分割的咖啡叶病害数据集。

下载链接:https://download.csdn.net/download/qq_40840797/88389334 数据集,一共1164张照片 随机选取几张照片及对应的目标标签 因为健康,所以标签为空

【嵌入式】使用MultiButton开源库驱动按键并控制多级界面切换

目录 一 背景说明 二 参考资料 三 MultiButton开源库移植 四 设计实现--驱动按键 五 设计实现--界面处理 一 背景说明 需要做一个通过不同按键控制多级界面切换以及界面动作的程序。 查阅相关资料,发现网上大多数的应用都比较繁琐,且对于多级界面的…

十大常见排序算法详解(附Java代码实现和代码解析)

文章目录 十大排序算法⛅前言🌱1、排序概述🌴2、排序的实现🌵2.1 插入排序🐳2.1.1 直接插入排序算法介绍算法实现 🐳2.1.2 希尔排序算法介绍算法实现 🌵2.2 选择排序🐳2.2.1 选择排序算法介绍算…

结构体运算符重载

1.降序 struct Point{int x, y;//重载比较符bool operator < (const Point &a) const{return x > a.x;//当前元素大时&#xff0c;是降序} };2.升序 struct Point{int x, y;//重载比较符 // bool operator < (const Point &a) const{ // return x…

如何初始化一个vue项目

如何初始化一个vue项目 安装 vue-cli 后 ,终端执行 vue ui npm install vue-cli --save-devCLI 服务 | Vue CLI (vuejs.org) 等一段时间后 。。。 进入项目仪表盘 设置其他模块 项目构建后目录 vue.config.js 文件相关配置 官方vue.config.js 参考文档 https://cli.vuejs.o…

【vue3】Suspense组件和动态引入defineAsyncComponent的搭配使用

假期第五篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 在app中定义子组件child //静态引入&#xff0c;网速慢的时候&#xff0c;父子组件也是同时渲染出来 <template><div><h3>APP父组件</…