2022年北航OO第一单元总结

一、三次作业总结

1. 第一次作业

1.1 需求分析

本次作业要求我们能够读入一个包含加、减、乘、乘方以及括号(其中括号的深度至多为 1 层)的单变量表达式,输出恒等变形展开所有括号后的表达式。

1.2 实现方案

首先考虑到数据的输入,我们可以在处理阶段开始就将读入的字符串中的空格全部替换,从而保证后续处理的稳定性并减少需要考虑到的表达式不同情况。
之后我们对表达式进行层次化结构分析,分为表达式层,项层,因子层;而因子层分为数字、幂函数与表达式因子。我们对整个表达式解析器设置迭代器Lexer从而简化对表达式的提取。解析器中又提供对三个层次解析的行为,为了简化整体计算量与复杂度,这里考虑在解析最小因子成项与表达式时,需要使用一种数据结构保证同类项的合并,因此我们使用HashMap作为三种解析行为的“通货”,在每层设计具体的化简功能即可,而且使用递归下降可以有效地保证程序的稳定性与可迭代性。最后只需要封装对HashMap的成表达式输出即可,同时也将性能与化简部分分隔。程序UML图如下:

image

其中程序实现的具体难点在于三处:输入串处理、同类项合并及高性能输出。
本程序将对字符串的处理使用解析器高层控制,迭代器底层具体控制,其实现对一个因子的完全提取并将得到的因子格式化处理后发送到解析器进行处理,实现方法为使用正则表达式。
同类项合并即为在解析器中封装HashMap之间的加与乘运算,其中减使用项的括号进行体现,幂方则使用循环乘运算进行。
输出则为若表达式有正项,则将其首位输出,负项输出减号。

1.3 结构分析

度量如下:

Class metrics:

class OCavg OCmax WMC
Term 1.00 1 3
Parser 7.20 11 72
Main 1.00 1 1
Lexer 2.67 10 24
Total 100
Average 4.35 5.75 25.00

Method metrics:

CogC ev(G) iv(G) v(G)
Total 205 34 104 109
Average 8.91 1.48 4.52 4.74

本次作业中由于在写代码前分析架构分析了好久,因此代码调试成功之后并没有出现BUG,进行程序反演与自己构建的不同数据进行测试之后,强测也得到了满分,也很幸运在互测中没有被Hack。同时递归下降的运用也使得迭代性较强。但由于HashMap通货的处理方法,使得程序无法处理三角函数等基本因子,这一点的改进在第二次作业中完成了实现。

1.4 测试思路

主要是使用连续的正负号,幂函数,表达式因子的不同构造,从而实现对代码稳定性的检测。

2. 第二次作业

2.1 需求分析

第二次作业需要完成对自定义函数与三角函数的嵌套多项式的化简,优化目标依然是最短输出。

2.2 实现方案

显然,由于加入了复杂的嵌套与三角函数,解析器不同解析方法的“通货”无法使用HashMap来进行处理,但由于每种解析方法的返回值都可以被看作一个表达式,即我们在Expr类中额外封装合并与乘积方法即可。除此之外,为了满足自定义函数的需求,我们可以在迭代器中增加处理函数的行为,这里为了告知顶层返回因子的类型,即是幂函数、表达式因子或者是自定义函数等等,添加FactorType类型。之后再封装工场类对返回类型加以处理,处理方式则为新建处理器调用解析递归获取最简形式即可。程序的UML图如下:

image

除此之外,本次作业将Factor类型的成员定义为两个HashMap,从而实现对幂和三角函数的分类包装,当然持续使用HashMap的原因还有就是其可以在增加的时候方便同类项合并。功能优化在第一次作业的基础上只是增加了sin(0) = 0 与 cos(0) = 1。最后的输出也是使用Expr类的toString() 方法,当然其是对Term.toString() 和 Factor.toString()的递归调用。

2.3 结构分析

Class metrics:

class OCavg OCmax WMC
Term 3.00 13 33
Parser 3.93 9 55
Main 2.00 2 2
Lexer 3.23 9 42
Power 1.00 1 5
Func 1.10 2 11
FacAndType 1.00 1 5
Total 199
Average 2.76 6.00 24.88

Method metrics:

CogC ev(G) iv(G) v(G)
Total 282 108 199 217
Average 3.92 1.50 2.76 3.01
2.4 测试思路

本次测试的表达式需要考虑到自定义函数和求和函数,为此我利用Python脚本对于sum函数和自定义函数生成了包含三角函数的表达式,最后也在强侧中的正确性达到了满分,由于舍弃了三角函数化简的部分数据的性能分,最终得到了95分,也算是一个我比较理想的成绩。

2.5 总结反思

本次作业迭代我对架构的改变就只是在对“通货”的改变上,其他则是对新增函数的完善,递归的处理让我的工作量下降了很多,但由于我在做本次作业时考虑到了嵌套并且此次强测没有相对应的点,也让我在第三次作业上由于过分自信导致出现了一个BUG,也是给第三次埋得一个坑吧。

3 第三次作业

3.1 需求分析

第三次作业中需要完成的任务为:读入一系列自定义函数的定义以及一个包含幂函数、三角函数、自定义函数调用以及求和函数的表达式,输出恒等变形展开所有括号后的表达式。注意函数中允许嵌套表达式。

3.2 实现方案

由于前两次作业的架构,这次作业我只是增加了对表达式是单项因子的判断,即如果是单项因子则拼接三角函数的时候不多加一层括号,如果是多项则添加, uml图与第二次作业一样。

3.3 结构分析

Class metrics:

class OCavg OCmax WMC
Term 3.00 13 33
Parser 3.93 9 55
Main 2.00 2 2
Lexer 3.23 9 42
Power 1.00 1 5
Func 1.10 2 11
FacAndType 1.00 1 5
Total 199
Average 2.76 6.00 24.88

Method metrics:

CogC ev(G) iv(G) v(G)
Total 283 108 201 219
Average 3.93 1.50 2.79 3.04

本次作业的各项复杂度相比前两次改变并不大,因此复杂度指标并没有太大的变化。

3.4 总结反思

由于第三次的结构和第二次的结构相似度太大,以及过分自信导致第二次作业的BUG在第三次强侧中被一个点直接攻破,BUG具体内容为sum中替换i时没有增加(),导致替换后若为负数,则无法偶次方变为正数,被数据点中 sum(i, -1, 3, sin(-i*i))攻破,导致这次作业最后一共获得了89分,也是给我开学本就难受第三周增添了更多的情绪吧。

架构设计体验

回忆这三周的OO作业,最艰难的便是第一周了,因为我在架构基础的搭建过程中不停地在方法中抉择,是使用树的数据结构还是使用大量的递归,是使用正则表式处理字符串还是暴力的自定义判断方法。而且在最后决定使用递归搭建之后,各函数之间的“通货”类型确立也花费了我大量的时间,可能也和我写代码的风格有关,我总是想把所有可能的情况演绎模拟枚举出来,觉得这样可以保证程序的健壮性,但不得不说,正则表达式这块涉及到的情况是真地难以固定。这也是导致我对第三周作业耿耿于怀的一个方面。

心得体会

通过本单元的学习,很大增强了我对字符串处理的相关能力。其实从刚开始接触到代码时,字符串的处理一直都是我的一个弱项,但现在我有了迭代器处理它的思想。同时我对递归也更加熟练了,因为本单元递归的使用确实很大减少了我的工作量,当然如果考虑时间空间复杂度,那就得另说啦。
这学期开始的OO作业伴随着我一个重要的阶段,现在是2022年3月23日13时34分,在回忆着前三周半发生的点点滴滴,无疑让我非常痛苦与困惑,直到现在我还是想不通生活中的好多好多问题,不过现在我已经回忆完了,这一单元的博客也写完啦,OO的学习很精彩,那么现在,就让我和自己和解吧!2021年末的期望已经落空了,但2022年依旧会很精彩!