首页/数据结构/03-stack-queue-array/表达式求值 🔗 在 Obsidian 中打开
数据结构 · 03-stack-queue-array

表达式求值

重要度 ⭐⭐ 表达式求值中缀转后缀逆波兰
速查
中缀→后缀用运算符栈:操作数直接输出;( 压栈;) 弹出直到 ((不输出);运算符优先级 > 栈顶则压、 则弹出继续比较。后缀求值用操作数栈,遇运算符弹两个算完压回(先弹出的是右操作数)。

核心概念

表达式求值是栈的经典应用。通过运算符栈操作数栈,可以实现中缀表达式的求值,也可以将中缀表达式转换为后缀(逆波兰)表达式。

类型又名运算符位置示例
前缀表达式波兰表达式操作数+ A B
中缀表达式常规表达式操作数之间A + B
后缀表达式逆波兰表达式操作数A B +
优先级运算符结合性
1(最低)+ -左结合
2* / %左结合
3^右结合
4(最高)(

关键定义

中缀转后缀算法(运算符栈)

  1. 从左到右扫描中缀表达式
  2. 操作数:直接输出到后缀表达式
  3. (:压入运算符栈
  4. ):弹出栈中运算符并输出,直到遇到 (( 弹出但不输出)
  5. 运算符
    • 若栈空或栈顶为 (,直接压栈
    • 若当前优先级 > 栈顶,压栈
    • 若当前优先级 $\leq$ 栈顶,弹出栈顶并输出,再与新栈顶比较,直到可以压栈

后缀表达式计算算法(操作数栈)

  1. 从左到右扫描后缀表达式
  2. 操作数:压入操作数栈
  3. 运算符:弹出两个操作数(先弹出的为右操作数),计算后将结果压栈
  4. 最终栈中剩余的唯一元素就是结果

手算示例

示例 1:中缀转后缀

将 $A + B * (C - D) - E / F$ 转为后缀。

步骤当前操作运算符栈输出(后缀)
1A输出A
2+压栈+A
3B输出+A B
4*压栈(优先级>+)+ *A B
5(压栈+ * (A B
6C输出+ * (A B C
7-压栈(栈顶是()+ * ( -A B C
8D输出+ * ( -A B C D
9)弹出直到(+ *A B C D -
10-弹出*、弹出+、压入--A B C D - * +
11E输出-A B C D - * + E
12/压栈(优先级>-)- /A B C D - * + E
13F输出- /A B C D - * + E F
结束弹出所有A B C D - * + E F / -

后缀表达式A B C D - * + E F / -

示例 2:后缀表达式计算

计算 6 5 2 3 + 8 * + 3 + *

6→[6] 5→[6,5] 2→[6,5,2] 3→[6,5,2,3]
+ → 2+3=5 → [6,5,5]
8 → [6,5,5,8]
* → 5*8=40 → [6,5,40]
+ → 5+40=45 → [6,45]
3 → [6,45,3]
+ → 45+3=48 → [6,48]
* → 6*48=288 → [288]

结果:288

示例 3:前缀表达式计算

计算 - + 2 * 3 4 / 8 2(从右往左扫描):

2→[2] 8→[2,8]
/ → 8/2=4 → [4]
4→[4,4] 3→[4,4,3]
* → 3*4=12 → [4,12]
2→[4,12,2]
+ → 2+12=14 → [4,14]
- → 14-4=10 → [10]  ← 结果 10

结果:10(注意:前缀从右往左扫描,栈顶为右操作数)

示例 4:加括号法辅助转换

(A+B)*C-D/(E+F) 转为后缀:

  1. 按优先级加括号:$(((A+B)\times C)-(D/(E+F)))$
  2. 把运算符移到相应右括号处:$(A\ B+)\to A\ B+$;$(A\ B+\ C\ *)\to A\ B+\ C\ *$;$(D\ E\ F+\ /)$
  3. 去括号得 A B + C * D E F + / -

常见考法

考法
  1. 中缀转后缀:手动模拟栈过程,写出后缀表达式。
  2. 后缀表达式求值:用操作数栈手动计算。
  3. 前缀表达式求值:从右往左扫描。
  4. 三种表达式相互转换:加括号法或栈法。
  5. 表达式树:后缀表达式对应表达式树的后序遍历。

易错点

易错清单
  1. 后缀计算左右操作数顺序:先弹出的是右操作数,后弹出的是左操作数
  2. 中缀转后缀优先级比较:$\leq$ 时要弹出(不是 $<$),如 + 遇到 + 也要弹出。
  3. 括号处理( 直接压栈,) 弹出直到遇到 (( 弹出但不输出
  4. 前缀计算扫描方向:前缀表达式从右往左扫描(不是从左往右)。
  5. 同级运算符处理:左结合运算符,同级时弹出栈顶(先算左边的)。
  6. 混淆输出顺序:后缀表达式操作数顺序与中缀相同,只是运算符位置改变。

核心结论

  1. 中缀转后缀用运算符栈:操作数直接输出,运算符按优先级压栈/弹出。
  2. 后缀计算用操作数栈:遇操作数压栈,遇运算符弹两个计算后压回(先弹出为右操作数)。
  3. 前缀计算从右往左:与后缀相反方向扫描。
  4. 后缀表达式无需括号:运算顺序由表达式本身确定。
  5. 加括号法快速转换:给中缀表达式按优先级加括号,再移动运算符。
  6. 栈的 LIFO 特性:保证了运算符按优先级正确应用。

记忆卡片

中缀转后缀遇 ( 和 ) 怎么处理?
( 直接压入运算符栈;) 弹出栈顶并输出直到遇到 (,且 ( 弹出但不输出。
3 4 + 5 * 的计算?
压 3、4 → + 弹 3、4 得 7 → 压 5 → * 弹 7、5 得 $7\times5=35$。
当前运算符优先级 ≤ 栈顶?
弹出栈顶并输出,继续比较直至当前优先级 > 栈顶或栈空/栈顶为 (,再压栈。
后缀计算的左右操作数?
先弹出的是右操作数,后弹出的是左操作数(如 - 时先弹 b 再弹 a,算 a-b)。

交互动画 · 中缀→后缀 & 后缀求值

中缀 → 后缀:操作数直接输出,运算符按优先级压栈/弹出
选择模式后点「下一步」逐步执行
转换比较用 $\leq$(++ 也要弹出);后缀求值先弹出的是右操作数

相关知识点

stack-basic-operations queue-basic-operations

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。