OO第一单元作业总结

郭灿超-24371169 2026-03-31 22:38:08

第一单元总结:表达式解析

一、前言

本单元的三次作业,让我从零开始构建了一个支持变量、函数、求导的表达式解析并展开括号化简的小程序。从上学期末尾学习的递归下降,到后来为了支持函数调用和指数函数进行AST重构,再到最后扩展到双变量和求导,每一步都充满了挑战和收获。

二、基于度量来分析自己的程序结构(最后一版没交上qwq

类名属性数方法数代码行数主要职责
Lexer3380词法分析,将输入转为Token流
Parser38200语法分析,递归下降构建AST
Symbol (interface)-310符号接口
VarSymbol1440变量符号(x或y)
ExpSymbol1560指数函数符号
Monomial18120单项式(因子的乘积)
NormalizedExpr115350多项式(单项式之和)
Recurrence4230递推公式存储
Main0130主程序入口
Tokentype--5保存Token

三、架构的迭代演进

第一次作业:基础的递归下降

第一次作业要求解析单变量表达式,支持加减乘、乘方和括号。设计很直观:

  • Lexer 将输入转为Token流。
  • Parser 按照文法递归下降,每个非终结符返回一个多项式(HashMap<Integer, BigInteger>,指数→系数)。
  • 多项式支持加法、减法、乘法、乘方,并自动合并同类项。

这个阶段的核心是把文法直接映射为代码,简单可靠。

第二次作业:引入函数调用和指数函数

第二次作业新增了自定义函数 f(x)、指数函数 exp(...) 和选择式因子。原有的多项式表示法(只包含x的幂)无法处理 exp(x) 这种非幂函数,因为 exp(x)exp((x^2)) 本质是不同的原子。于是我进行了一次重构:

  • 引入 Symbol 接口,将变量 xexp(参数) 都视为原子符号。
  • Monomial 表示多个符号的乘积(如 x * exp(y))。
  • NormalizedExpr 表示多项式。

这个重构让表达式树变成了符号的多项式,将不同种类的因子统一为符号,后续的代入、求导都变得统一。

函数调用通过 substitute 实现:将定义中的 x 替换为实参表达式。选择式因子则先计算 A-B 是否为零,再选择分支。

第三次作业:双变量与求导

第三次作业将变量扩展为 xy,新增了求导算子 dxdygrad 和递推函数 f{n}(x)

双变量的支持很简单:将 VarSymbol 改为携带名称(xy),多项式运算完全通用。

求导的实现是关键:

  • NormalizedExpr 中添加 derivative(String var)(即求导) 方法。
  • 对常数求导得0,对变量求导得1或0,对 exp(f) 求导得 exp(f) * f',对乘积求导使用乘积法则。
  • grad 直接展开为 dx + dy

递推函数则单独存储 f{0}f{1} 和递推公式,在调用时递归展开(序号≤5,可缓存)。

四、Bug与测试

遇到的Bug

  1. 第二次作业:选择式因子的恒等判断错误。原因是 MonomialequalscompareTo 没有正确实现,导致相同内容但顺序不同的单项式被认为不等。改用 TreeMap 后解决。
  2. 第三次作业:第一次求导时忽略了链式法则,对 exp(f) 只算了自身,忘了乘 f'。修正为 exp(f) * f'
  3. 递推函数替换错误:调用 f{n}(g) 时,对 f{n-1}(arg) 中的 arg 没有替换外部实参。修正为递归前先对 arg 做代入。

测试策略

  • 白盒单元测试:为每个方法(尤其是 derivativesubstitute)编写小样例。
  • 随机生成测试:用 大模型 制作评测机,生成随机样例进行测试。
  • 互测靶向:阅读他人代码,针对薄弱点(如前导零、连续符号、嵌套选择式)构造用例,有时借助大模型帮忙debug。

五、优化与AI使用

优化点

  • 合并同类项:使用 TreeMap 自动排序,每次运算后清理零系数项。
  • 快速幂pow 用快速幂减少乘法次数。
  • 递推缓存:对已展开的 f{k}(arg) 结果缓存,避免重复递归。
  • 输出简化:系数为1时省略,常数项单独输出,exp 参数必要时加括号。

AI辅助

  • 三次作业中约40%的代码由AI生成(主要是框架和算法思路)。
  • AI帮助我定位了选择式因子的bug,并生成了随机测试脚本。
  • 互测中发现有同学代码存在明显的AI特征(过度优化、大量Javadoc),这些代码往往隐藏着不易发现的错误。
  • 互测中使用AI帮助同学debug

六、心得体会

  1. 递归下降:文法直接映射为代码,简单清晰,扩展性好。新增语法只需增加对应方法,不影响已有逻辑。
  2. 数据结构决定上层建筑:第二次作业的重构让我深刻体会到,用一个合适的抽象(符号→单项式→多项式)可以大幅简化后续开发。
  3. 测试要自动化:手动测试根本无法覆盖所有情况,随机生成+自动验证是保证正确性的利器。

七、对课程的改进建议

  • 提前介绍设计模式:Visitor模式可以让求导、化简等操作更优雅,但第一次作业时还不知道,后来重构才用上。
  • 提供测试工具:官方如果能给出一个随机生成器或基准测试,学生可以更早发现自己的问题。
  • 鼓励代码互评:互测仅限于找bug,如果还能互相提改进建议,学习效果会更好。

八、结语

本单元的三次作业让我在压力中快速成长。感谢课程组和互测小伙伴们,这段经历将成为我学习面向对象编程路上的宝贵财富。

...全文
62 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

302

社区成员

发帖
与我相关
我的任务
社区描述
2026年北航面向对象设计与构造
java 高校
社区管理员
  • 孙琦航
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧