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


    e71dcac11cb24182941533453241f369.gif

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

    6a78491801a74bbd8d932659b06e11db.gif#pic_center

    目录

    ​编辑

    ​编辑

    回顾 🧸

    ​编辑

    中缀表达式🀄

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

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

    通用的中缀转后缀算法⭐

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

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



    6a78491801a74bbd8d932659b06e11db.gif#pic_center

    6e2e58c7c0eb4abba046a09b8b95d377.png

    回顾 🧸

    "温故而知新"

    通过思维导图回顾一下我们学了什么,我们先学了什么是线性结构,栈(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

    cf314ae038f54056a0c28bf4408d9fa9.png

    中缀表达式🀄

    我们通常看到的表达式如: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)),显式表达了计算次序我们注意到每一对括号,都包舍了一组完整的操作符和操作数,让我们看看如何将其转换成前后缀表达式吧~

    0d102a3763224d53a976a65a93d18fb0.png


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

    ✨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']

    4d52ca2a00de4600b398de060cd69776.png

    流程示意图: 

    b2e4372780974525acdbfc4b00958b91.png

    图解: 

    b1e85e62409c49b39e61d6e371c1613c.png

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

    1. class Stack:#Stack---->ADT
    2. def __init__(self):
    3. self.items =[]
    4. def isEmpty(self):
    5. return self.items == []
    6. # 满足这些属性(行为)的是栈
    7. def push(self,item):
    8. self.items.append(item)
    9. def pop(self):
    10. return self.items.pop()
    11. def peek(self):
    12. return self.items[len(self.items)-1]
    13. #
    14. def size(self):
    15. return len(self.items)
    16. def infixToPostfix(infixexpr):
    17. # 记录操作符优先级
    18. prec = {}
    19. prec["*"] = 3
    20. prec["/"] = 3
    21. prec["+"] = 2
    22. prec["-"] = 2
    23. prec["("] = 1
    24. opStack = Stack()
    25. postfixList = []
    26. # 解析表达式到列表
    27. tokenList = infixexpr.split()
    28. for token in tokenList:
    29. # 操作数
    30. if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789":
    31. postfixList.append(token)
    32. # (
    33. elif token == "(":
    34. opStack.push(token)
    35. # )
    36. elif token == ")":
    37. topToken = opStack.pop()
    38. while topToken != '(':
    39. postfixList.append(topToken)
    40. topToken = opStack.pop()
    41. # 操作符
    42. else:
    43. while (not opStack.isEmpty()) and \
    44. (prec[opStack.peek()] >= prec[token]):
    45. postfixList.append(opStack.pop())
    46. opStack.push(token)
    47. while not opStack.isEmpty():
    48. # 操作符
    49. postfixList.append(opStack.pop())
    50. # 合成后缀表达式字符串
    51. return " ".join(postfixList)
    52. print(infixToPostfix("A + B * C "))

    运行代码测试结果 :

    a202fa65cdca435aacd20d90c9e52e4a.png

    fef1bda618054673ac4bad37ce3d3ba9.gif

  • 相关阅读:
    关于agi中的Function Calling深入解析
    LeetCode-380. Insert Delete GetRandom O(1) [C++][Java]
    蚂蚁发布金融大模型:两大应用产品支小宝2.0、支小助将在完成备案后
    TypeScript - 字符串的字面类型
    【Spring】AOP的三种方式
    国际站腾讯云服务器登录后的界面在哪里看到?
    线段树入门+例题详解
    制作一个简单HTML电影网页设计(HTML+CSS)
    Django Celery异步任务队列
    计算机毕业设计ssm基于SSM框架在线电影评论投票系统3gr0f系统+程序+源码+lw+远程部署
  • 原文地址:https://blog.csdn.net/Aileenvov/article/details/133467887