数据结构与算法(Python版)九:表达式转换

中缀表达式转换为前缀和后缀形式

看子表达式(B*C)的右括号, 如果把操作符*移到右括号的位置, 替代它, 再删去左括号, 得到BC*, 这个正好把子表达式转换为后缀形式

进一步再把更多的操作符移动到相应的右括号处替代之,再删去左括号,那么整个表达式就完成了到后缀表达式的转换
在这里插入图片描述

同样的, 如果我们把操作符移动到左括号的位置替代之, 然后删掉所有的右括号,也就得到了前缀表达式

在这里插入图片描述

所以说, 无论表达式多复杂, 需要转换成前缀或者后缀, 只需要两个步骤

将中缀表达式转换为全括号形式将所有的操作符移动到子表达式所在的左括号(前缀)或者右括号(后缀)处,替代之,再删除所有的括号
在这里插入图片描述

通用的中缀转后缀算法

首先我们来看中缀表达式A+BC, 其对应的后缀表达式是ABC+

操作数ABC的顺序没有改变。操作符的出现顺序,在后缀表达式中反转了由于*的优先级比+高,所以后缀表达式中操作符的出现顺序与运算次序一致。

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

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

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

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

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

再看看(A+B)*C, 对应的后缀形式是AB+C*

这里+的输出比*要早,主要是因为括号使得+的优先级提升,高于括号之外的*

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

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

总结下, 在从左到右扫描逐个字符扫描中缀表达式的过程中, 采用一个栈来暂存未处理的操作符

这样, 栈顶的操作符就是最近暂存进去的, 当遇到一个新的操作符, 就需要跟栈顶的操作符比较下优先级, 再行处理。

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

操作符单词包括*/+-()而操作数单词则是单字母标识符A、 B、 C等。

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

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

A+B*C =split=> [‘A’, ‘+’, ‘B’, ‘*’, ‘C’]

从左到右扫描中缀表达式单词列表

如果单词是操作数,则直接添加到后缀表达式列表的末尾
如果单词是左括号“(”,则压入opstack栈顶
如果单词是右括号“)”,则反复弹出opstack栈顶
操作符,加入到输出列表末尾,直到碰到左括号
如果单词是操作符“*/±”,则压入opstack栈顶

  • 但在压入之前,要比较其与栈顶操作符的优先级
  • 如果栈顶的高于或等于它,就要反复弹出栈顶操作符,加入到输出列表末尾
  • 直到栈顶的操作符优先级低于它

中缀表达式单词列表扫描结束后, 把opstack栈中的所有剩余操作符依次弹出, 添加到输出列表末尾

把输出列表再用join方法合并成后缀表达式字符串, 算法结束。

通用的中缀转后缀算法:实例

在这里插入图片描述

代码:

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"))
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python表达式求值是指根据给定的Python表达式计算出结果的过程。它涉及解析表达式,按照运算符的优先级和结合性进行计算,并返回最终的结果。 在上述引用中,提到了一种方法来编程演示如何一步一步地计算Python表达式。这种方法涉及使用ast模块解析表达式为抽象语法树(AST),然后逐步求值AST节点。首先,使用ast.parse()将字符串解析为AST。然后,找到一个首先要求值的节点,并使用eval(compile(node, '', 'eval'))对其求值。求值结果可以转换回AST节点,并用结果节点替换当前节点。接着,使用codegen.to_source从修改后的AST生成修改后的代码字符串,并继续相同的过程,直到树中只有一个节点。 这种方法可以逐步展示Python表达式的求值过程。它可以用于教学目的,帮助学生理解表达式的求值方式。然而,需要注意的是,这种方法可能无法处理某些复杂的行为,比如列表理解。在处理这些复杂情况时,可能需要采用其他方法或工具。 总结:Python表达式求值是根据给定的表达式计算结果的过程。使用ast模块可以解析表达式为AST,并通过逐步求值AST节点来展示求值过程。然而,对于复杂的行为,可能需要其他方法或工具来处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [逐步跟踪Python表达式求值](https://blog.csdn.net/weixin_30982943/article/details/112956371)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值