从后缀表达式到无冗余括号的中缀表达式转换指南

从后缀表达式到无冗余括号的中缀表达式转换指南

本文详细介绍了如何将后缀表达式转换为中缀表达式,并在此过程中智能地移除冗余括号。通过采用基于的算法,并结合运算符的优先级和结合性规则,我们能够精确判断何时需要添加括号以保持表达式的语义,从而生成一个既正确又简洁的中缀表达式。

在数学和编程中,表达式的表示形式多种多样,其中后缀表达式(逆波兰表示法)因其无需括号即可明确运算顺序的特性,在编译器和解释器中广为应用。然而,为了人类的可读性,我们通常需要将其转换回中缀表达式。此转换过程的挑战在于如何有效地管理括号,避免生成如 ((a*b)+(c*d)) 这样带有冗余括号的表达式,而应生成更简洁的 a*b+c*d。本文将深入探讨一种基于栈的算法,该算法不仅能完成后缀到中缀的转换,还能智能地移除冗余括号。

核心原理:优先级与结合性

移除冗余括号的关键在于理解运算符的优先级和结合性。

优先级(Precedence):不同运算符有不同的执行顺序。例如,乘除的优先级高于加减。在 a + b * c 中,b * c 会先计算。如果需要先计算 a + b,则必须使用括号:(a + b) * c。结合性(Associativity):相同优先级的运算符的执行顺序。左结合性:从左到右计算。例如,减法和除法是左结合的。a – b – c 等价于 (a – b) – c。右结合性:从右到左计算。例如,幂运算是右结合的。a ^ b ^ c 等价于 a ^ (b ^ c)。

我们的目标是,只有当运算符的优先级或结合性规则要求时,才添加括号。

算法实现:基于栈的转换

该算法使用一个栈来存储中间结果。在处理后缀表达式时,遇到操作数就入栈,遇到运算符就弹出栈顶的两个操作数进行组合,然后将新生成的中缀表达式及其对应的“最外层运算符”重新入栈。

1. 运算符优先级与类型定义

首先,定义运算符的优先级和列表。

precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}operators = ['-', '+', '*', '/', '^']

这里,^ 表示幂运算,优先级最高,加减最低。

达芬奇 达芬奇

达芬奇——你的AI创作大师

达芬奇 50 查看详情 达芬奇

2. 判断左操作数是否需要括号

leftNeedParenthesis 函数用于判断当前运算符的左操作数是否需要被括号包围。

def leftNeedParenthesis(current: str, leftOperator: str):    # 如果左操作数没有关联的运算符(即它本身是一个操作数,或整个表达式的左边界),则不需要括号。    if leftOperator is None:        return False    # 如果当前运算符的优先级高于左操作数的最外层运算符,则左操作数需要括号。    # 例如:(a+b)*c,当处理*时,左操作数是a+b,其最外层运算符是+。*的优先级高于+,所以a+b需要括号。    return precedence[current] > precedence[leftOperator]

3. 判断右操作数是否需要括号

rightNeedParenthesis 函数用于判断当前运算符的右操作数是否需要被括号包围。这需要同时考虑优先级和结合性。

def rightNeedParenthesis(current: str, rightOperator: str):    # 如果右操作数没有关联的运算符(即它本身是一个操作数,或整个表达式的右边界),则不需要括号。    if rightOperator is None:        return False    # 情况一:当前运算符优先级高于右操作数的最外层运算符。    # 例如:a*(b+c),当处理*时,右操作数是b+c,其最外层运算符是+。*的优先级高于+,所以b+c需要括号。    if precedence[current] > precedence[rightOperator]:        return True    # 情况二:当前运算符优先级低于右操作数的最外层运算符。    # 例如:a+b*c,当处理+时,右操作数是b*c,其最外层运算符是*。+的优先级低于*,所以b*c不需要括号。    elif precedence[current] < precedence[rightOperator]:        return False    # 情况三:当前运算符与右操作数的最外层运算符优先级相等。    # 此时需要考虑结合性。    else:        # 减法是左结合的:a - b - c 等价于 (a - b) - c。        # 当处理第一个-时,左操作数是a,右操作数是b-c。b-c需要括号。        if current == "-" and rightOperator == "-":            return True        # 除法是左结合的:a / b / c 等价于 (a / b) / c。        # 当处理第一个/时,左操作数是a,右操作数是b/c。b/c需要括号。        elif current == "/" and rightOperator == "/":            return True        # 幂运算是右结合的:a ^ b ^ c 等价于 a ^ (b ^ c)。        # 当处理第一个^时,左操作数是a,右操作数是b^c。b^c需要括号。        elif current == "^" and rightOperator == "^":            return True        # 对于其他相同优先级的运算符(如加法+和+,乘法*和*),不需要额外括号。        # 例如:a+b+c 等价于 (a+b)+c。当处理第一个+时,右操作数是b+c,不需要括号。        # 例如:a*b*c 等价于 (a*b)*c。当处理第一个*时,右操作数是b*c,不需要括号。        return False

4. 后缀转中缀主函数

postfix_to_infix 函数是整个转换的核心。它遍历后缀表达式,利用栈和上述的括号判断函数来构建中缀表达式。

def postfix_to_infix(postfix: str) -> str:    stack = [] # 栈用于存储 (中缀表达式字符串, 最外层运算符)    for c in postfix:        if c.isalnum(): # 如果是操作数(字母或数字)            stack.append((c, None)) # 操作数本身没有运算符,用None表示        else: # 如果是运算符            # 弹出右操作数和其关联的运算符            (operand2, lastUsedOperator2) = stack.pop()            # 弹出左操作数和其关联的运算符            (operand1, lastUsedOperator1) = stack.pop()            # 根据规则判断左操作数是否需要加括号            if leftNeedParenthesis(c, lastUsedOperator1):                operand1 = "(" + operand1 + ")"            # 根据规则判断右操作数是否需要加括号            if rightNeedParenthesis(c, lastUsedOperator2):                operand2 = "(" + operand2 + ")"            # 组合成新的中缀表达式,并将当前运算符作为其最外层运算符入栈            stack.append((operand1 + c + operand2, c))    # 栈中最终只剩下一个元素,即完整的无冗余括号的中缀表达式    (result, _) = stack.pop()    return result

示例与使用

假设我们有一个后缀表达式 ab*cd*+,它表示 (a*b) + (c*d)。让我们跟踪 postfix_to_infix(“ab*cd*+”) 的执行过程:

a 入栈:[(‘a’, None)]b 入栈:[(‘a’, None), (‘b’, None)]* 运算符:弹出 (‘b’, None) 作为 operand2弹出 (‘a’, None) 作为 operand1leftNeedParenthesis(‘*’, None) -> FalserightNeedParenthesis(‘*’, None) -> False组合为 a*b,入栈:[(‘a*b’, ‘*’)]c 入栈:[(‘a*b’, ‘*’), (‘c’, None)]d 入栈:[(‘a*b’, ‘*’), (‘c’, None), (‘d’, None)]* 运算符:弹出 (‘d’, None) 作为 operand2弹出 (‘c’, None) 作为 operand1leftNeedParenthesis(‘*’, None) -> FalserightNeedParenthesis(‘*’, None) -> False组合为 c*d,入栈:[(‘a*b’, ‘*’), (‘c*d’, ‘*’)]+ 运算符:弹出 (‘c*d’, ‘*’) 作为 operand2弹出 (‘a*b’, ‘*’) 作为 operand1leftNeedParenthesis(‘+’, ‘*’) -> precedence[‘+’] (1) > precedence[‘*’] (2) -> False (因为乘法优先级更高,a*b 不需要括号)rightNeedParenthesis(‘+’, ‘*’) -> precedence[‘+’] (1) > precedence[‘*’] (2) -> False (同理,c*d 不需要括号)组合为 a*b+c*d,入栈:[(‘a*b+c*d’, ‘+’)]

最终结果为 a*b+c*d。

完整代码示例

precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}operators = ['-', '+', '*', '/', '^']def leftNeedParenthesis(current: str, leftOperator: str):    if leftOperator is None:        return False    return precedence[current] > precedence[leftOperator]def rightNeedParenthesis(current :str, rightOperator: str):    if rightOperator is None:        return False    if precedence[current] > precedence[rightOperator]:        return True    elif precedence[current]  str:    stack = []    for c in postfix:        if c.isalnum():            stack.append((c, None))        else:            (operand2, lastUsedOperator2) = stack.pop()            (operand1, lastUsedOperator1) = stack.pop()            if leftNeedParenthesis(c, lastUsedOperator1):                operand1 = "(" + operand1 + ")"            if rightNeedParenthesis(c, lastUsedOperator2):                operand2 = "(" + operand2 + ")"            stack.append((operand1 + c + operand2, c))    (result, _) = stack.pop()    return result# 接收用户输入并处理# postfix_expression = input("请输入后缀表达式 (无空格): ").replace(" ", "")# print(f"转换后的中缀表达式: {postfix_to_infix(postfix_expression)}")# 示例测试print(f"ab*cd*+ -> {postfix_to_infix('ab*cd*+')}") # 预期: a*b+c*dprint(f"abc++ -> {postfix_to_infix('abc++')}")     # 预期: a+b+cprint(f"ab-c- -> {postfix_to_infix('ab-c-')}")     # 预期: (a-b)-cprint(f"abc^- -> {postfix_to_infix('abc^-')}")     # 预期: a-b^cprint(f"ab^c^ -> {postfix_to_infix('ab^c^')}")     # 预期: a^(b^c)print(f"a bc+*d- -> {postfix_to_infix('abc+*d-'.replace(' ', ''))}") # 预期: a*(b+c)-d

注意事项与总结

输入格式:本算法假设输入的后缀表达式是有效的,且操作数是单个字母或数字,运算符是预定义的字符。如果操作数可以是多位数字或变量名,需要修改 c.isalnum() 的判断逻辑,并可能需要一个更复杂的词法分析器。运算符集合:如果需要支持更多运算符(如取模 %),需要更新 precedence 字典和 operators 列表,并根据其优先级和结合性调整 rightNeedParenthesis 函数。时间复杂度:该算法对后缀表达式进行一次线性扫描,栈操作(入栈、出栈)的平均时间复杂度为 O(1)。因此,整体时间复杂度为 O(N),其中 N 是后缀表达式的长度,效率较高。错误处理:本教程未包含对无效后缀表达式的错误处理。在实际应用中,需要考虑栈为空时弹出元素等异常情况。

通过上述基于栈的算法,我们能够高效且准确地将后缀表达式转换为无冗余括号的中缀表达式,这对于构建解析器、编译器或其他需要表达式处理的系统具有重要意义。理解运算符优先级和结合性是实现这一转换的核心。

以上就是从后缀表达式到无冗余括号的中缀表达式转换指南的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/569052.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小米 REDMI 手机:老机型无法升级金沙江电池,努力过但技术难度实在太大
上一篇 2025年11月10日 05:02:57
人工智能技术对儿童带来哪些影响?
下一篇 2025年11月10日 05:03:01

相关推荐

  • OPPO A3 Pro自动亮度异常解决方法 OPPO A3 Pro屏幕调节技巧

    先检查设置和传感器状态,再排查软硬件问题。关闭省电模式和自动亮度调节,手动调整亮度至50%-70%;清洁屏幕顶部传感器区域,检查手机壳是否遮挡;重启手机,排除第三方应用干扰,更新系统版本;若问题依旧,可能存在非原装屏幕或硬件故障,需联系售后检测。 OPPO A3 Pro出现自动亮度异常,多数情况是设…

    2026年9月21日
    100
  • iPhone 17 Pro Max如何开启应用分身功能

    iPhone 17 Pro Max不支持原生应用分身,可通过官方企业版应用如“企业微信”或“QQ轻聊版”实现双开,此方法安全稳定且推荐优先使用;部分应用可能提供TestFlight测试版以支持多账号登录,但依赖开发者支持且存在不稳定性;第三方分身工具因企业证书易被吊销及隐私泄露风险,强烈不建议使用。…

    2026年9月21日
    000
  • 如何在服务器上优化mysql安装

    优化MySQL需从系统环境、配置参数、存储引擎到日常维护多层面入手,首先确保内存合理分配、选用XFS等高性能文件系统、关闭非必要服务并调整内核参数;其次在MySQL配置中优先使用InnoDB引擎,科学设置innodb_buffer_pool_size、innodb_log_file_size、max…

    2026年9月21日
    000
  • Linux怎么监控特定进程的运行状态

    Linux怎么监控特定进程的运行状态Linux怎么监控特定进程的运行状态Linux怎么监控特定进程的运行状态Linux怎么监控特定进程的运行状态

    监控Linux进程需综合使用ps、top、htop、pgrep和systemctl等工具,结合资源占用、进程状态、日志输出和进程数量判断是否异常,并通过systemd的Restart机制或看门狗脚本实现自动重启,同时利用journalctl、sar、atop及Prometheus+Grafana等方…

    2026年9月21日 用户投稿
    000
  • iPhone 16 Pro如何设置不同铃声给联系人

    在iPhone 16 Pro上为特定联系人设置专属铃声和振动模式,只需进入“通讯录”编辑该联系人,选择“电话铃声”和“振动”选项进行自定义,还可单独设置“短信铃声”,所有设置通过iCloud同步保留。 给iPhone 16 Pro上的特定联系人设置专属铃声很简单,不需要用到电脑或第三方工具。你直接在…

    2026年9月21日
    100
  • 苹果手机密码忘记如何解决

    一、通过Apple ID重设密码 Apple ID是苹果用户的核心账户,可用于找回或重置iPhone的锁屏密码。操作流程如下: 尝试输入密码:在iPhone锁屏界面多次输入错误密码后,系统会提示“iPhone已停用,请稍后再试”。 选择“需要帮助”:当出现锁定提示时,屏幕上通常会显示“忘记密码”或“…

    2026年9月21日
    300
  • Linux如何限制用户执行特定命令

    Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令

    首选sudo进行命令限制,因其灵活且可审计;通过visudo配置精确的用户权限,结合白名单、命令别名和!语法实现允许或拒绝特定命令;同时防范绕过手段如全路径执行、间接调用、脚本执行等,需多层防御并辅以日志监控。 在Linux环境中,限制用户执行特定命令,最直接有效且灵活的方法通常是利用 sudo 权…

    2026年9月21日 用户投稿
    100
  • 抖音商城是哪个公司在运营

    抖音商城的运营主体揭晓 抖音商城由北京微播视界科技有限公司负责运营。 作为抖音背后的母公司,字节跳动通过其全资子公司——微播视界,全面掌舵抖音平台及其电商板块的日常运作。依托雄厚的技术积累与多元化的业务布局,为用户打造流畅、智能且高效的购物环境。 抖音商城究竟是什么? 抖音商城是抖音App内嵌的一站…

    2026年9月21日
    100
  • iPhone 17如何快速清理存储空间

    首先通过系统推荐一键优化释放8-12GB空间,再重点清理微信缓存、合并重复照片并开启优化存储,最后深度清理Safari缓存、删除大型App及关闭自动下载,可高效腾出数十GB存储。 虽然目前还没有iPhone 17,但根据2025年最新的iOS系统清理方法,无论你使用的是哪款iPhone,都可以通过以…

    2026年9月21日
    100
  • iPhone SE 2022常见发热原因及处理方法 科普指南

    iPhone SE 2022 发热主因包括高性能任务、边充边用、高温环境、厚手机壳、后台程序及电池老化;正常使用下发热属常见现象,通过停止高耗能操作、移至阴凉处、取下手机壳、开启低电量模式可快速降温;长期建议避免边充边玩、选用轻薄壳、定期清理系统、更新 iOS 及检查电池健康,若待机过热或有鼓包异味…

    2026年9月21日
    100
  • 小红书视频封面不显示怎么办 小红书封面加载与设置技巧

    小红书视频封面不显示通常由上传设置、网络或缓存问题导致。先检查网络稳定性,确保封面尺寸为1080×1440像素(3:4比例),格式为JPG或PNG且不超过5MB;上传时使用Wi-Fi避免中断,在编辑页面务必点击“设为封面”并确认保存;发布后若未显示可等待几分钟刷新或重启App查看。优先尝试重新编辑封…

    2026年9月21日
    100
  • 抖音奈雪点单小程序怎么弄的

    抖音奈雪点单小程序是专为抖音用户打造的一款便捷点单工具,依托抖音平台生态,让用户无需跳转即可轻松完成奈雪饮品的选购与下单。为提升用户体验,奈雪茶庄同步推出了详尽的操作说明和使用指引。 小程序使用步骤 1. 打开抖音APP,在搜索栏输入“奈雪点单”查找相关小程序,或通过抖音首页的“附近的小程序”入口快…

    2026年9月21日
    100
  • 从 API 响应中提取元素并在 Java 中使用

    本文介绍了如何在 Java 中解析 API 响应,并从中提取特定元素的值。以 JSON 格式的响应为例,演示了如何使用 Jackson 库将 JSON 字符串转换为 Java 对象,并提取所需的数据,例如账户 ID,以便在后续操作中使用。 在 Java 开发中,经常需要与 API 进行交互,并从 A…

    2026年9月21日
    100
  • 苹果痛失AI大将,Siri关键负责人转投Meta

    苹果痛失AI大将,Siri关键负责人转投Meta苹果痛失AI大将,Siri关键负责人转投Meta苹果痛失AI大将,Siri关键负责人转投Meta苹果痛失AI大将,Siri关键负责人转投Meta

    近日有消息显示,%ignore_a_1%公司负责siri改革的关键高管ke yang已确认离职,并将加入竞争对手meta。这一变动不仅为苹果雄心勃勃的ai计划蒙上了一层阴影,也再次凸显了其在留住顶尖人才方面面临的严峻挑战。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 Dee…

    2026年9月21日 用户投稿
    200
  • 访问DeepSeek官方网站 deepseek在线版免费登录

    答案:DeepSeek在线版免费登录入口位于官网https://chat.deepseek.com/sign_in,用户可通过手机号验证码或微信授权登录,新用户免注册,登录后自动创建账户并同步多端数据,支持网页和APP使用。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 De…

    2026年9月21日
    100
  • 荣耀X50 GT如何设置动态壁纸 荣耀X50 GT个性化主题操作指南

    首先通过“主题”App设置动态壁纸,可选系统内置的风景、科技或动漫类动态壁纸,预览后下载应用即可;接着能将相册中的视频设为动态桌面,需在动态壁纸页面导入本地视频,裁剪调整后生成并应用;最后还可搭配主题风格、图标、锁屏和字体进行个性化设置,整体操作简单快捷,几分钟完成,但使用高清或长视频可能增加电量消…

    2026年9月21日
    100
  • Windows11提示“应用程序无法正常启动(0xc000007b)”怎么解决_Windows11应用程序启动0xc000007b修复方法

    首先使用SFC工具修复系统文件,再重新安装Visual C++运行库,接着更新DirectX组件,最后可借助专用DLL修复工具解决0xc000007b错误。 如果您尝试在Windows 11上启动某个应用程序,但弹出“应用程序无法正常启动(0xc000007b)”的错误提示,则可能是由于系统文件损坏…

    2026年9月20日
    100
  • iPhone 15 Pro如何删除多余Apple ID账户

    首先需明确,iPhone 15 Pro不支持直接删除多个Apple ID,只能通过退出登录移除。具体操作为:进入「设置」点击顶部Apple ID,选择「退出登录」并确认,可保留或不保留数据副本;若要永久注销账户,须访问appleid.apple.com,登录后申请删除并记录访问代码,经7天等待期后账…

    2026年9月20日
    100
  • 零跑D16官宣 增程版配80度超大电池 明年上半年上市

      10月16日,零跑汽车正式公布其全新旗舰车型零跑d19的内饰设计与核心技术信息。作为基于零跑自研“旗舰d平台”打造的高端车型,零跑d19计划于2025年第四季度完成内饰解密,2026年上半年开启预售并正式上市。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSee…

    2026年9月20日
    100
  • Safari浏览器无法切换账号怎么办 Safari浏览器账号切换异常解决方法

    无法切换账号通常与系统设置、iCloud状态或缓存有关;2. 确保启用快速用户切换以实现多用户登录;3. 检查iCloud账户登录状态并同步Safari数据;4. 清除网站数据或使用无痕模式排除缓存问题。 如果你在使用Safari浏览器时遇到无法切换账号或切换异常的问题,这通常与系统用户设置、iCl…

    2026年9月20日
    100

发表回复

登录后才能评论
关注微信