当前位置: 首页 > backend >正文

栈的应用:表达式求值

一、核心问题:表达式求值的难点

对于像 3*(7-2)# 这样的表达式,直接计算会面临 “运算顺序” 的问题:

  • 先算括号里的 7-2,还是先算乘法?
  • 如何处理运算符的优先级(乘除高于加减)?
  • 如何匹配括号(括号内的要优先计算)?

栈的作用就是 “管理运算顺序”

  • 用两个栈:
    • OPND 栈:存操作数(如 372 )和中间结果(如 515 )。
    • OPTR 栈:存运算符(如 *(- )和边界符(如 # )。
  • 通过 “比较运算符优先级”,决定是 “压栈等待” 还是 “弹出计算”。

二、关键规则:算符优先关系表

 

这张表是 “指挥中心”,决定运算符的优先级:

  • 表格里的 θ₁ 是 栈顶运算符θ₂ 是 当前扫描到的运算符
  • 比较结果:
    • <:当前运算符优先级更高 → 压入 OPTR 栈,等待后续计算。
    • >:栈顶运算符优先级更高 → 弹出栈顶运算符,从 OPND 取数计算。
    • =:括号匹配(如 ( 和 ) 相遇),弹出栈顶的 (,继续扫描。

举个简单例子:

  • 栈顶是 +θ₁),当前运算符是 *θ₂):查表格,+ 和 * 的交叉是 < → * 优先级更高,* 压栈。
  • 栈顶是 *θ₁),当前运算符是 +θ₂):查表格,* 和 + 的交叉是 > → * 优先级更高,先弹出 * 计算。

三、算法步骤(结合图片里的流程)

以 3*(7-2)# 为例,完整走一遍流程:

1. 初始化
  • OPTR 栈压入 #(作为表达式的 “起始边界符”)。
  • OPND 栈为空。
  • 扫描指针指向表达式第一个字符 '3'
2. 循环处理(直到扫描到 # 且栈顶也是 #

核心逻辑

  • 遇到 操作数(如 372 )→ 压入 OPND 栈。
  • 遇到 运算符(如 *(- )→ 查 “优先关系表”,决定是 “压栈” 还是 “计算”。

逐步演示

步骤扫描字符 ch操作说明
1'3'压入 OPND 栈OPND: [3]OPTR: [#]
2'*'比较 OPTR 栈顶 # 和 * → <* 压入 OPTR 栈 → OPTR: [#, *]
3'('比较 OPTR 栈顶 * 和 ( → <( 压入 OPTR 栈 → OPTR: [#, *, (]
4'7'压入 OPND 栈OPND: [3, 7]
5'-'比较 OPTR 栈顶 ( 和 - → <- 压入 OPTR 栈 → OPTR: [#, *, (, -]
6'2'压入 OPND 栈OPND: [3, 7, 2]
7')'比较 OPTR 栈顶 - 和 ) → >弹出 -,计算 7-2=5,结果压入 OPND → OPND: [3, 5];然后比较栈顶 ( 和 ) → =,弹出 (
8'#'比较 OPTR 栈顶 * 和 # → >弹出 *,计算 3*5=15,结果压入 OPND → OPND: [15]
9'#'扫描结束,返回 OPND 栈顶结果 15
3. 终止条件

当扫描到 #,且 OPTR 栈顶也是 # 时,循环结束,OPND 栈顶就是最终结果。

四、代码逻辑解析(结合图片里的函数)

以下是核心函数的逻辑拆解(对应图片里的 EvaluateExpression 函数):

1. 初始化栈
InitStack(OPTR); Push(OPTR, '#'); // OPTR 栈初始化,压入 #
InitStack(OPND); ch = getchar();  // OPND 栈初始化,读第一个字符
2. 循环处理表达式
while (ch != '#' || GetTop(OPTR) != '#') { // 没扫描完或栈顶不是 #if (!In(ch)) { // ch 不是运算符 → 压入 OPNDPush(OPND, ch); ch = getchar(); } else { // ch 是运算符 → 比较优先级switch (Precede(GetTop(OPTR), ch)) { case '<': // 当前运算符优先级高 → 压栈Push(OPTR, ch); ch = getchar(); break;case '>': // 栈顶运算符优先级高 → 弹出计算Pop(OPTR, theta); // 弹出运算符Pop(OPND, b); Pop(OPND, a); // 弹出两个操作数Push(OPND, Operate(a, theta, b)); // 计算后压入结果break;case '=': // 括号匹配 → 弹出 (,继续扫描Pop(OPTR, x); ch = getchar(); break;}}
}
3. 返回结果
return GetTop(OPND); // OPND 栈顶就是结果

五、关键函数说明

  1. In(ch):判断 ch 是否是运算符(+-*/()# )。
  2. Precede(θ₁, θ₂):查 “优先关系表”,返回 <> 或 =
  3. Operate(a, theta, b):执行运算(如 a + ba * b ),注意顺序(a 是栈底的数,b 是栈顶的数,比如 7-2 中 a=7b=2 )。

六、总结

栈在表达式求值中的核心作用是 “管理运算顺序”

  • 用 OPTR 栈 “暂缓” 低优先级的运算符,保证高优先级的先计算。
  • 用 OPND 栈存操作数和中间结果,随时弹出参与计算。
  • 整个过程靠 “算符优先关系表” 指挥,实现自动遵循 “先乘除后加减、先括号内后括号外” 的规则。
http://www.xdnf.cn/news/12097.html

相关文章:

  • AIGC 基础篇 高等数学篇 03 中值定理与导数应用
  • 系统巡检常见工作
  • 标准IO及相关函数介绍
  • 中电金信:从智能应用到全栈AI,大模型如何重构金融业务价值链?
  • [Java 基础]面向对象-继承
  • QML技术优势
  • GuessNumber
  • CET6 仔细阅读 24年12月第三套-C2 美的定义这一块
  • 【opnecv】检测桌子上多余的物品
  • 《复制粘贴的奇迹:小明的原型工厂》
  • python打卡第44天
  • AI大模型学习三十二、飞桨AI studio 部署 免费Qwen3-235B与Qwen3-32B,并导入dify应用
  • CSS 选择器全解析:分组选择器/嵌套选择器,从基础到高级
  • 关于如何运用AI的思考
  • Day44 Python打卡训练营
  • ATM存取钱项目
  • 【DeepSeek 学大模型推理】Fused Residual LayerNorm with Reduce-Scatter
  • MySQL事务:从ACID特性到高并发优化的深度解析
  • day 44
  • K8S主机漏洞扫描时检测到kube-服务目标SSL证书已过期漏洞的一种永久性修复方法
  • 【论文写作】如何撰写基于模型拼接(A+B)的创新性论文
  • leetcode 二叉搜索树中第k小的元素 java
  • SiFli 567+emmc Standby休眠报错问题
  • 重装系统+驱动+磁盘分区
  • day19 leetcode-hot100-37(二叉树2)
  • 5.29-6.4解决问题归纳
  • 银行用户信誉等级
  • 前端面试宝典---vite原理解析
  • Numpy——结构化数组和Numpy文件
  • 【电赛培训课程】电子设计竞赛工程基础知识