你不知道的秘密——深入解析前缀,中缀,后缀表达式

本文带你深入理解前缀、中缀、后缀表达式的概念,详细解析中缀变后缀的过程及原因。揭示中缀与后缀表达式之间的内在联系,提供快速转换技巧,让你轻松掌握表达式转换之道。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每次学习到数据结构中的“栈”的时候,都或多或少地会碰到前缀、中缀、后缀表达式的知识。然而,你是否有过这样的疑问:
符号栈里面,优先级大的在上面还是小的在上面来着?优先级是必须大于等于还是必须大于?虽然我知道怎么把中缀变后缀,但是为什么要这么变啊?额,每次学了会,会了忘,好苦恼啊!
本篇博客就带你一起揭开这些疑问,本篇博客不会机械化地告诉你具体如何操作,而是告诉你为什么要这么操作,原理在哪里。

一、熟其面才能见其理

1. 我们首先来看一下,什么是前缀、中缀、后缀表达式:

中缀表达式: 234
后缀表达式:234
前缀表达式:234

PS:简单介绍下,前中后的划分依据为两个数字的操作符处于两个数字的前面,中间还是后面。其中,中缀表达式为我们日常生活中常见的表达形式。

2. 重要操作过程:

我们来一起回顾一下几个重要的操作过程。

后缀表达式求值过程:

从左到右扫描后缀表达式:遇到数字就将其压入栈中;遇到操作符,则取出栈顶的两个元素(栈顶元素为a,另一个为b。),并计算b 操作符 a的取值,并将结果重新压入栈中。扫描整个表达式结束后,栈中数值即为整个表达式的结果。

前缀表达式求值过程:

从右向左扫描前缀表达式:其他操作除了(栈顶元素为b,另一个为a。)与后缀表达式求值过程相同,不再赘述。

中缀表达式转换为后缀表达式过程:

从左向右扫描中缀表达式,遇到数字直接输出;
遇到操作符,就压入栈中,如果此时栈中已经存在操作符,则比较栈顶操作符和待压入操作符的优先级,如果待压入操作符的优先级高于栈顶操作符的优先级,则执行压栈操作。否则,弹出栈顶操作符并输出。
继续比较新的栈顶操作符和待压入操作符,直到将栈中所有操作符都弹出或待压入操作符的优先级大于栈顶操作符优先级。
扫描完毕后,如果栈里还存在操作符则将栈内所有操作符依次弹出并输出。最后得到的输出结果即为中缀表达式所对应的后缀表达式。

中缀表达式转换为前缀表达式过程:

从右向左扫描中缀表达式,遇到数字直接输出;
遇到操作符,除了将“待压入操作符的优先级高于栈顶操作符的优先级”改为“待压入操作符的优先级不低于栈顶操作符的优先级”外和“中缀变后缀的过程”相同。
扫描完毕,得到输出后,再将输出表达式左右对调,即为最后的结果。

二、深入解析,探究谜底。

在第一部分,我们一起简要回顾了一下前缀、中缀、后缀表达式的相关知识。就当一个热身运动。众所周知,虽然前缀表达式比后缀表达式出现的早,但是,现在较为常用的却是后缀表达式,所以,下面我们也主要以后缀表达式为例子。

谜题1: 中缀变后缀的过程中,为什么要保持栈中操作符的优先级从栈顶开始到栈底结束,优先级逐渐严格递减?

可能很多人都有这样的疑问:为什么待压入操作符的优先级必须大于栈顶操作符优先级,等于也不行,小于也不行,可能主要纠结于为什么等于不行!

谜题1解答:

要解答这个问题,首先要纠正一个我们平常所持有的惯用思维。我们一直认为:乘除优先级相同,加减优先级相同,且乘除大于加减。
其实,这是不准确的,准确来说,在一个表达式中没有任何两个优先级相等的操作符,比如:13/4,其实,我们会先算乘法,再算除法。没错,这就是“从左到右”法则。
所以,其实“操作符存储栈”里面的操作符是严格遵循从栈顶到栈底,优先级逐次递减的。比如:1+23/4,从左向右扫描到”/”号的时候,栈中状态为 +,栈顶元素为,这时,“/”号的优先级是低于号的,所以,号会弹出,然后将”/”号压入栈中。

另外,我们一直没有谈到有()的情况该怎么办,其实()会强制提高符号的优先级,比如:2+3(4+56)7,在这里面,由于有()存在,其实第三个操作符+的优先级要大于第二个操作符的优先级。所以,操作符栈中,操作符存在的最大数量为4,此时栈的状态为(从底到顶): +(+,当然了,当遇到)括号时,所有(括号之上的操作符必须强制弹出。

PS:同理,你可以想想为什么中缀变前缀的时候,就变成了不低于,而不是高于?记得它是从右向左扫描哦。

谜题2:中缀表达式和后缀表达式是不是有着某种奇妙的联系?我可不可以快速地将中缀表达式变换为后缀表达式?

在这里,我们为了简化问题的分析过程,我们将只考虑不存在括号的情况。

谜题2解答:

“投机取巧是成功的第一步”,不不!应该是:善于发现规律并利用规律提高效率的人,很Good!额,请原谅我的词穷。

有没有联系?这个肯定有。就是变个身嘛。我们从表面上可以看出来,中缀表达式和后缀表达式的数字排列顺序是完全相同的,只是符号的位置和顺序不太一样。

这不废话嘛!但是,正是这句废话,却是我们寻找快速转换的切入点。如果要实现快速转换,只需要快速确定操作符的位置和顺序,那么就大功告成了!

如何操作呢?
首先,将整个表达式分为许多连续的模块。这些模块是下面三种模式中的一种:
模式一: +/ a / b 。(其中,a,b为操作数。)
模式二:/+a。(其中,a为操作数。)
模式三:+/a/b1/b2....../bn
我们可以看到,上面前两种模式的操作符的优先级都是递增的。第二个模式,只有一个操作符,额,也就无所谓递增了。第三种模式较为特殊,以+/-符号开头,然后接下来是一连串的*或/符号。
划分原则为:有模式三就化模式三,有模式一就化模式一,最后考虑模式二。
然后,将模式一的式子变为:ab/+,将模式二的式子变为:a/+,将模式三的式子改为:ab1/b2/......bn/+

实战练习:

3+46/38+963+5
转换为后缀表达式为:
3463/+896+35+

到这里,前缀、中缀、后缀表达式的介绍就结束了,如果你还有什么疑问或者好的建议,欢迎留言,一起交流,一起讨论。

### 前缀中缀后缀表达式的练习题 以下是针对前缀中缀后缀表达式的常见练习题目,涵盖了它们的转换与求值过程: #### 转换类题目 1. **将下列中缀表达式分别转换为前缀表达式后缀表达式:** - \( A + B \times C \)[^1] - \( (A + B) \times (C - D) \)[^2] - \( A / B + C \times D \)[^3] 2. **已知后缀表达式,将其还原为中缀表达式并验证结果:** - 输入后缀表达式 `AB+C*`,写出对应的中缀表达式[^4]。 3. **给定前缀表达式,将其转换为中缀表达式:** - 输入前缀表达式 `+ * A B C`,写出对应的中缀表达式[^5]。 #### 求值类题目 1. **计算以下后缀表达式的值:** - 输入后缀表达式 `8 2 + 5 *`,计算其结果[^3]。 2. **计算以下前缀表达式的值:** - 输入前缀表达式 `- + 7 8 9`,计算其结果[^2]。 3. **输入一个复杂的中缀表达式,通过程序实现将其转换为后缀表达式后再求值:** - 中缀表达式:\( ((A + B) \times C) - (D / E) \)[^4]。 #### 应用类题目 1. **设计一个函数,能够接收任意形式的表达式前缀中缀后缀),并通过或其他数据结构完成求值。** 2. **编写一段代码,利用表达式树的方法将中缀表达式转换为后缀表达式,并给出具体步骤说明。** --- ```python # 示例代码:使用来计算后缀表达式的值 def evaluate_postfix(expression): stack = [] operators = set(['+', '-', '*', '/']) for char in expression.split(): if char not in operators: stack.append(int(char)) else: b = stack.pop() a = stack.pop() if char == '+': result = a + b elif char == '-': result = a - b elif char == '*': result = a * b elif char == '/': result = int(a / b) stack.append(result) return stack[-1] expression = "8 2 + 5 *" print(evaluate_postfix(expression)) # 输出应为 50 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值