302
社区成员
发帖
与我相关
我的任务
分享姓名:程子涵
学号:24371407
课程:面对对象设计与构造
本单元三次作业在能力上从括号多项式逐步扩展到含 exp、选择式、自定义函数(HW2),再到求导因子与递推定义的 f(HW3)。架构上采用「递归下降解析 → Node#eval 建树求值 → SymExpr 规范式化简与输出」的主线,将文法与代数语义分离。本文结合度量数据、类关系、迭代中的 bug 与互测体会,做一小结。
| 类(HW3) | 属性/字段(约) | 方法数(约) | 代码行数(约) | 说明 |
|---|---|---|---|---|
Main | 0(静态为主) | 10+ | 190 | 读入、规范化、解析函数体/递推、异常与输出 |
SymExpr + 内部 MonoKey | 4 + 3 | 20+ | 400 | 规范式 ∑ c·x^k·exp(arg),合并同类项 |
Expression_Parser + FunctionEnv 等 | 若干 | 25+ | 330 | 解析、Node 求值、f/f' 与递推 |
Polynomial(遗留) | 1 | 多 | 156 | HW1 风格,HW2/HW3 中未再作为主路径 |
HW1 规模更小:Main≈47 行、Polynomial≈172 行、Expression_Parser≈117 行,合计约 330 行量级;HW2 引入 SymExpr 后核心逻辑上移到符号层,解析器行数与圈复杂度明显上升。
| 方法 | 行数(约) | 圈复杂度(约) | 说明 |
|---|---|---|---|
Main.normalizeSignsInPlace | 25 | 6~8 | 连续 +/- 规范化,分支多,曾易写死循环 |
Expression_Parser.parseFactor(HW3) | 20+ | 10+ | x/(/[/exp/f/常数/求导 分发 |
SymExpr.multiply | 25 | 4~6 | 双重循环合并 MonoKey |
SymExpr.toExprString / appendMonomial | 40+ | 6~8 | 系数、x 与 exp 的必要括号 |
观察:解析层 parseFactor 随作业迭代分支持续增加(HW3 增加求导、递推环境下的 f),是维护热点;代数层 SymExpr 方法以数据合并为主,分支相对可控。
SymExpr 专责「单项式键 + 系数」的表示与运算;Expression_Parser 专责文法与 eval 闭包,职责边界清晰。Main 在 HW3 中承担了较多输入拆解与合法性判断,内聚略弱,若再迭代可拆出 InputReader / FormatValidator。SymExpr 的构造与运算,单向依赖;SymExpr 不依赖解析器,依赖方向健康。HW3 中 FunctionEnv 将递推与记忆化封装在解析包内,避免 Main 直接操作备忘录,略有改善。Expression_Parser 的 WMC 最高,与「因子种类多」一致;CBO 上 Main 与 Expression_Parser、SymExpr 相连,属预期。下列为示意类图(手工整理,非 IDEA 一键逆向)。表达「谁依赖谁」即可。
classDiagram
class Main {
+main()
-normalize()
-parseFunctionDefinition()
}
class Expression_Parser {
<<interface>> Node
+parseExpressionNode()
-parseFactor()
}
class SymExpr {
-Map terms
+add() multiply() pow()
+toExprString()
}
Main ..> Expression_Parser : 创建
Main ..> SymExpr : 输出
Expression_Parser ..> SymExpr : eval 得到
Main:负责 IO、去空白、符号规范化,以及 HW3 的递推/函数体读入。设计意图是入口薄、异常统一。Expression_Parser:递归下降;Node 用 eval(SymExpr argForX) 统一表达式因子与函数体内 x 的代入,避免为每种因子写重复遍历。SymExpr:不可变(逻辑上)规范式;MonoKey 绑定 x 指数与 exp 内层参数,乘法对应指数相加、exp 内层相加,契合作业恒等式。Polynomial:HW1 遗留;HW2 起主路径已迁移到 SymExpr,保留便于对照或工具类使用。优点:解析与语义分层,扩展因子时在 parseFactor/eval 增加分支即可。
缺点:Expression_Parser 单类偏长;HW3 后求导与递推与通用因子耦合在同一类中,若再增加语法,可考虑按因子类型拆子解析器(需权衡作业规模)。
| 作业 | 新增能力 | 架构做法 |
|---|---|---|
| HW1 | 表达式展开为多项式,x^k、括号、乘方 | Expression_Parser → Polynomial(HashMap<指数, 系数>),快速幂 pow |
| HW2 | exp(因子)、[(A==B)?C:D]、f(因子)、f(x)=… | 引入 SymExpr + MonoKey;解析返回 Node,选择式用 (A-B) 是否恒为 0 判定;f 对实参求值后代入;可选 functionEvalMemo 避免重复展开 |
| HW3 | 求导因子、递推定义 f(n)、更多格式约束 | FunctionEnv 持有普通 f 与递推式;evalRecursiveFunction + RecurrenceKey 记忆化;parseDerivativeFactor;非法时输出 Wrong Format(与 HW2 静默退出策略不同,以作业要求为准) |
Polynomial 到 SymExpr:不是小改,而是表示模型的更换——从「单变量幂」到「幂 × exp(参数)」的直和。重构动机是 HW2 文法已无法用单一 HashMap<Integer, BigInteger> 表达。Polynomial;HW2 起返回 Node,延迟求值到 eval,使 f 的实参与定义体解耦。SymExpr 运算写全,后期 HW3 主要在解析器上堆分支;若早预判 HW3,可把「函数环境」抽象得更早。ln(exp中的内容)SymExpr 的合并思想、Node 求值链、括号与输出规则的模式。ln(Factor);语义上 ln 与 exp 是否可化简为多项式取决于课程定义——若只允许形式展开,需在 SymExpr 增加新因子类型或扩展 MonoKey,改动面大于加 +。ln 这类需新等价关系的运算,应预先设计可扩展的因子枚举,避免继续膨胀 parseFactor 的 if-else。| 特征 | 问题表现 | 涉及类/方法 | 原因 | 设计层面改进 |
|---|---|---|---|---|
预处理中 */^ 后跟 - | 长时间运行或 TLE | Main.normalizeSignsInPlace | 某些分支未推进 index,对 -1*-2 类串死循环 | 规范循环不变式:每次迭代要么缩短串,要么 i++;对边界写单测 |
| 选择式/等价判定 | WA | Expression_Parser.evalChoice / SymExpr.subtract | 恒等判定依赖化简后为零,MonoKey 合并或 exp(0) 未消干净会导致误判 | 统一「零元」与 exp(0)=1 的入口,避免多处特判不一致 |
| HW3 格式 | RE 或 Wrong Format | Main 读入与校验 | 行数、关键字、禁止出现在函数体中的结构等与 HW2 不同 | 按文档单独分支,避免复用 HW2 的「静默退出」逻辑到 HW3 |
normalizeSignsInPlace:行数不多,但分支嵌套多、圈复杂度高,易漏 index++。SymExpr.add:逻辑以 merge 为主,线性、模式重复,出错率低。降复杂度:对符号规范化可拆成「删除 ++」「折叠 +-」等小函数;解析器可对 parseFactor 用 switch/表驱动(若 Java 版本允许)或按首字符分派到私有方法,减少单方法内的分支数。
x、深层括号与 exp 嵌套。exp 合并弱,测 exp(a)*exp(b) 与 exp(a+b)。n 与函数行是否匹配、互测 cost 与长度限制(若平台有)。parseFactor 顺序与特判 性价比高。exp(0) 消去、同类项合并,减少输出与中间项规模。SymExpr.pow 对单项快速路径 + 一般情况二进制幂,控制次数。f(实参) 的记忆化(若启用),减少重复展开。SymExpr 不变式内完成,不破坏「先规范再输出」的流程,回归时重点测乘法与 exp 合并即可。CheckEquiv 小工具)与课程样例全集回归。以下比例为个人主观估计,表示「相关模块里有多少思路或代码片段曾参考过大模型的建议」,非精确统计。整体保持辅助为主、核心手写,故占比刻意不报高。
| 作业 | 正确性相关(约) | 性能/优化相关(约) | 说明 |
|---|---|---|---|
| HW1 | 约 18% | 约 15% | 递归下降与 Polynomial 主体为自己实现;曾用模型核对 BigInteger 用法、括号与符号处理的边界说法,少量语句经提示后改写。 |
| HW2 | 约 12% | 约 18% | SymExpr / MonoKey 与解析器架构与绝大部分代码为手写;曾让模型帮忙梳理 exp 合并、exp(0) 与选择式恒等判定的注意点,以及 toExprString 里括号规则的对照检查,未整文件生成。 |
| HW3 | 约 18% | 约 13% | 递推与求导分支多,用模型辅助阅读题意、把递归与记忆化拆成步骤说明,再在 IDE 里自己落代码;性能上仅讨论过记忆化是否必要、未依赖模型做复杂改写。 |
代码之外的使用:整理本单元博客提纲、把长句改顺、英文类名/术语核对;偶尔问「递归下降遇到某类因子该怎么接」这类概念题。效果上能省一点查资料时间,但公测与强测是否通过仍依赖本地调试与对拍,模型不能代替逐条用例验证。
声明:未使用大模型批量生成整份作业工程;核心逻辑与 bug 修复过程以自己调试为主。
exp 参数的单项式键」,过早优化成多项式会阻碍扩展。\t(若题目允许),或按规则拒绝非法字符。StringBuilder 上扫描,将 ++、+-、-+、-- 及 */^ 与紧随其后的 +/- 按规则折叠;关键是为每种模式定义是否移动游标,避免死循环。f(实参)、exp 嵌套、选择式 是否单独计费。