表达式是由操作数、运算符和界限符组成的有意义的序列。在计算机科学中,表达式的表示形式对算法设计和程序实现有着重要影响。常见的表达式表示形式有三种:前缀表达式、中缀表达式和后缀表达式。
表达式类型 | 定义 | 示例 |
---|---|---|
前缀表达式 | 运算符位于操作数之前 | + 3 4 |
中缀表达式 | 运算符位于操作数之间 | 3 + 4 |
后缀表达式 | 运算符位于操作数之后 | 3 4 + |
中缀表达式是我们日常使用最频繁的表达式形式,运算符位于两个操作数中间。
中缀表达式的求值是一个比较复杂的过程,需要考虑运算符的优先级和结合性。下面以表达式"3+4*2"为例说明求值过程:
中缀表达式转后缀表达式是一个重要的操作,通常使用栈来实现。算法步骤如下:
后缀表达式又称逆波兰表达式,运算符位于操作数之后。
后缀表达式的求值使用栈来实现,算法步骤如下:
以后缀表达式"3 4 2 * +"为例:
前缀表达式又称波兰表达式,运算符位于操作数之前。
前缀表达式的求值同样使用栈,但扫描顺序是从右到左,算法步骤如下:
以前缀表达式"+ 3 * 4 2"为例:
核心思路:把中缀表达式倒过来处理,转换逻辑类似"中缀转后缀",最后再翻回来。
案例:中缀表达式 (3+4)*2
转前缀
2*(4+3)
(注意括号也要反转,右括号变左括号)2*(4+3)
,遇到操作数2
先存起来;*
,栈空直接入栈;(
(原右括号),入栈;4
存起来,遇到+
,栈顶是(
,入栈;3
存起来,遇到)
(原左括号),弹出+
与(
,此时栈顶是*
,弹出*
;2 4 3 + *
* + 4 3 2
(即前缀表达式)口诀:倒着看中缀→当后缀处理→结果再倒过来
核心思路:从左到右扫描,遇到运算符就把后面两个操作数用括号包起来。
案例:前缀表达式 + * 3 4 5
转中缀
+
:后面需要两个操作数,先找后面的元素;*
:再找两个操作数3
和4
,组成 (3*4)
;5
:此时+
需要的两个操作数已齐,将(3*4)
和5
用+
连接,组成 ((3*4)+5)
;(3*4)+5
可视化过程:
+ * 3 4 5 → + (3*4) 5 → (3*4)+5
↑ ↑↑ ↑ ↑ ↑
运算符 操作数对 包裹第一层 最终结果
核心思路:用栈存储运算符,遇到操作数直接扔出去,遇到运算符就和栈顶比优先级。
案例:中缀表达式 3+4*2/(1-5)
转后缀
3
:操作数,直接存到结果→[3]
+
:栈空,入栈→栈[+]
4
:操作数,存结果→[3,4]
*
:优先级高于栈顶+
,入栈→栈[+,*]
2
:操作数,存结果→[3,4,2]
/
:优先级等于*
,弹出*
存结果→[3,4,2,*]
,然后/
入栈→栈[+,/]
(
:直接入栈→栈[+,/,(]
1
:操作数,存结果→[3,4,2,*,1]
-
:栈顶是(
,入栈→栈[+,/,(,-]
5
:操作数,存结果→[3,4,2,*,1,5]
)
:弹出栈中运算符直到(
,弹出-
存结果→[3,4,2,*,1,5,-]
,(
出栈/
和+
,存结果→[3,4,2,*,1,5,-,/,+]
3 4 2 * 1 5 - / +
动画演示逻辑:
中缀:3 + 4 * 2 / (1 - 5)
后缀:3 4 2 * 1 5 - / +
核心思路:倒着看后缀表达式,用栈存操作数,遇到运算符就弹出两个操作数组合。
案例:后缀表达式 3 4 2 * 1 5 - / +
转前缀
+ / - 5 1 * 2 4 3
3
、4
、2
先入栈→栈[3,4,2]
*
:弹出2
和4
,组合成*42
,入栈→栈[3,*42]
1
、5
入栈→栈[3,*42,1,5]
-
:弹出5
和1
,组合成-15
,入栈→栈[3,*42,-15]
/
:弹出-15
和*42
,组合成/*42-15
,入栈→栈[3,/*42-15]
+
:弹出/*42-15
和3
,组合成+3/*42-15
,入栈→栈[+3/*42-15]
+ 3 / * 4 2 - 1 5
(格式化后)关键技巧:
a b +
倒序后是+ b a
)转换类型 | 核心工具 | 关键步骤 | 案例(以3+4*2为例) |
---|---|---|---|
中缀→前缀 | 栈+反转 | 反转中缀→按中缀转后缀处理→结果反转 | 中缀(3+4)*2 →前缀*+342 |
前缀→中缀 | 栈+包裹 | 从左到右扫描,遇到运算符就包裹后面两个操作数 | 前缀+*342 →中缀(3*4)+2 |
中缀→后缀 | 栈+优先级 | 操作数直接存,运算符按优先级入栈弹出 | 中缀3+4*2 →后缀342*+ |
后缀→前缀 | 栈+逆序 | 倒序扫描后缀,操作数入栈,运算符弹出组合成新字符串 | 后缀342*+ →前缀+*342 |