OO课程第一单元总结
第一次作业
第一次作业主要考察简单多项式导函数的求解。
由于题目规定输入格式均为正确,且导函数结构较为简单,总体难度上较低。
主要思路为:先去除输入中的空白字符,再通过在Pre3中学得的Java正则表达式,对输入进行识别,通过某些数据结构储存起来,再进行求导与输出。
- 基于度量的程序结构分析
-
类图及简要说明
![image]()
MainClass类:负责输入与输出;Expression类:识别并存储表达式,同时使用Hashmap的结构存储Term类;Term类:识别并存储单个项。
-
代码规模
![image]()
因为第一次作业所需要实现的功能较少,因此在不考虑后续迭代开发的情况下,程序也相对简单,代码规模较小。
-
方法复杂度
![image]()
第一次作业较为简单,整体上结构复杂度较低。其中
Term.outPut()方法由于偷懒沿用了第一次实验课上写的toString代码,含有一个较长的if-else语句,因此复杂度相对较高。 -
类复杂度
![image]()
Expression类与Term类的构造方法中都含有对表达式的识别,可能是造成复杂度高的主要原因。
-
- 优缺点分析
- 优点
- 能够在无BUG的情况下正常运行。
- 能够有一定意识地使用面向对象的思路去实现程序。
- 实现了同类项合并,去0等的简单优化。
- 缺点
- 图一时的方便没有给后续的迭代开发留下余地。
- 代码中存在一些意义不明的设计。如
Expression类中使用Hashmap的方式来存储Term类,但key值却就是Term类中的cov属性,多此一举;如添加了output()方法而非重载toString()方法,降低可读性;等等。 - 优化上不够到位,没有考虑到正项提前,也没有想到可以将“x**2”化为“x*x”来缩减长度。
- 优点
- 程序BUG分析
- 自己程序的BUG
我的第一次作业未在强测与互测中发现BUG。 - 寻找他人程序BUG采用的策略
第一次互测,没有做好相应的准备,只好采用了效率较低的手动构造数据的黑箱测试,数据数量少且强度低。但在机缘巧合之下竟然真的发现了一个BUG。
- 自己程序的BUG
第二次作业
第二次作业在第一次作业的基础上添加了对简单正余弦函数的求导。
该次作业较第一次难度上有了较大的提升,我当时却没有很重视,最后是赶着ddl提交的作业,也因此被查出了许多BUG。主要的难点在于:1.正则表达式已经无法满足输入的读取要求,需要重新学习新的表达式读取方式,我采用了课程组推荐的递归下降语法分析;2.对Java数据结构的掌握有一定要求。
- 基于度量的程序结构分析
-
类图及简要说明
![image]()
第二次作业在第一次作业的基础上增加了Factor类,且与Term类一同实现了Cloneable接口。MainClass类:负责递归下降识别输入表达式,并给出输出;Expression类:存储表达式,同时使用Hashmap的结构存储Term类;Term类:存储单个项,同时使用Hashmap的结构存储Factor类。Factor类:存储单个因子。
-
代码规模
![image]()
第二次作业的代码行数直接上涨到508行,是第一次作业的整整三倍。一方面是递归下降语法分析的代码占用了150行左右的代码,另一方面是由于
Term类中重写了equal()与hashCode()方法。此外,大量的for-each语句也占据了相当多的代码行数。 -
方法复杂度
![image]()
![image]()
一方面,我书写的递归下降的语法分析中有较多的if-else语句,拉高了复杂度。另一方面,由于对Hashmap数据结构的不够了解,代码中出现了大量的for-each迭代,对复杂度的提高也有较大的影响。
-
类复杂度
![image]()
MainClass类额外负责了递归下降语法分析,造成复杂度较大,在面向对象的思想中,我应当新增一个类专门负责递归下降语法分析,这里是我处理的不好。Expression类与Term类中有大量的for-each迭代,同样拉高了复杂度。
-
- 优缺点分析
由于需要重构的原因,我的第二次作业完成得相当仓促,在运行效率于最终性能的表现上都非常差劲,因此在这里我想谈谈缺点。- 缺点
- BUG很多,实际上,在提交截止前的十几分钟里我刚刚修改了一个相当严重的BUG(详见后续的BUG分析)。
- 运行效率低,括号多层嵌套时会出现TLE。根本原因是我对Hashmap的掌握不到位,在程序中有大量不必要且可以被优化的迭代。
- 尽管有simplify()的优化方法,但其实际起到的作用微乎其微,程序化简的效果不尽人意。
- 难以体现面向对象的开发思想。类过少导致程序耦合度较高。
- 缺点
- 程序BUG分析
- 自己程序的BUG
- 由于对Hashmap的理解不到位,我对
Term类中重载的equals()与hashCode()方法存在BUG。在hashCode()中,我会将每个因子的toString().hashCode()的返回值累和作为该项的哈希值。在合并同类项时,这种方法会导致形如“x5*sin(x)2”与“x2*sin(x)5”两项的错误合并(字符串“x5”的hash值+“sin(x)2”的hash值=“x2”的hash值+“sin(x)5”的hash值)。 - toSting()方法的实现不当。当一个因子为表达式因子,且该因子表达式toString()的返回值为空时(实际上该表达式的值应为0),会产生错误。例如,项输出(因子1)(因子2,且因子2满足上述条件)(因子3)时,实际会输出(因子1)**(因子3)。
- 遇到多次嵌套的输入时会产生TLE。这是由于程序内部采用了大量迭代而导致的。
- 由于对Hashmap的理解不到位,我对
- 寻找他人程序BUG采用的策略
第二次互测借用了其他同学提供的评测机。当然,我自己也手动构造了一些数据。
- 自己程序的BUG
第三次作业
第三次作业在第二次作业的基础上添加了对正余弦函数嵌套组合函数的求导。
由于在第二次作业的BUG修复阶段,为了纠正TLE的BUG,我再次对程序进行了一次重构,且考虑到了后续的迭代开发,因此第三次作业实际上也是较为轻松的一次作业,但由于新增了对错误格式的判断,因此也造成了一些困扰。
- 基于度量的程序结构分析
-
类图及简要说明
![image]()
第三次作业在第二次作业的基础上,首先将各个类中无序的hashMap改为有序的treeSet结构,且对大部分类实现了Comparable接口,改写了compareTo()方法。其次为了便利深克隆,将必要的类实现了Serializable接口。MainClass类:负责递归下降识别输入表达式,并给出输出;Expression类:存储表达式,同时使用treeSet的结构存储Term类;Term类:存储单个项,同时使用treeSet的结构存储Factor类。Factor类:存储单个因子。
-
代码规模
![image]()
第三次作业的代码行数为634行,增长幅度不大。主要增长内容为对错误格式的判错。
-
方法复杂度
![image]()
![image]()
复杂度方面,主要是递归下降语法分析相关的方法复杂度较大。此外,由于第三次作业将因子/项的添加与化简合并的方式,因此addTerm()与addFactor()的复杂度较高。实际上可以通过增加方法来降低复杂度。
-
类复杂度
![image]()
类复杂度方面和第二次作业相差不大,普遍飘红。主要问题还是在于对面向对象的设计思想的理解与实践的不足。
-
- 优缺点分析
- 优点
- 运行效率尚可,面对多层嵌套可以较快地给出结果。
- 实现了较为简单但效果显著的化简,在多数测试点中都获得了不错的分数。
- 缺点
- 存在少量且不应当的BUG。
- 难以体现面向对象的开发思想。类过少导致程序耦合度较高。
- 优点
- 程序BUG分析
- 自己程序的BUG
- 格式判断上存在错误。遗漏了对左右括号适配的识别,在强测中出现了错误。
- 过度优化造成了BUG。具体表现为将sin(x**2)输出为sin(x*x)。
- 寻找他人程序BUG采用的策略
第三次互测没有找到他人程序的BUG。
- 自己程序的BUG
重构经历总结
第一单元的三次作业,三次重构,每一次重构都相当痛苦,但又令我受益良多。
第一次作业使用了正则表达式的识别方法,整体结构也相当简单,无法支持后续迭代开发;第二次作业参考了研讨课上其他同学分享的架构,有意识地为后续的开发预留了空间,但在自己实现时却因为对Java语言的不熟悉而遭遇了许多问题,最终因为时间不足而仓促提交;第三次作业的重构,更多地加入了我自己的想法,尽管仍有些许BUG,在化简上也仍有提升的空间,但大方向上已经没有问题。
心得体会
三次作业的过程,尤其是第二次作业的过程,实话实说,给我的感觉相当痛苦。打个比方,就好像把不会游泳的我粗暴地推进水里,无视我几乎溺水的事实,强迫我学会游泳一样。当我不会递归下降的时候,当我遇到hashmap迭代出错的时候,当我遇到深度克隆的时候,我只能摸爬滚打地到网上寻找资料。这可能确实是大学学习的特色吧。从小学到初高中,总有一本教材可以参考,有标准答案可以解惑。虽然怀疑这样的网络自学是否真的能有效提升我的代码水平,提高我的代码质量,但我实际上确实学到了不少东西,也算是受益匪浅吧。
另外,对于作业的完成,我也有一些感悟。最主要的是,在考虑优化的同时,不要忽视正确性。毕竟性能分只占0.2。有时候,花大量的时间优化性能反而会导致时间不够用或正确性的降低。从功利性的角度出发,在强测中保持正确性的人,绝对比性能分高但正确率低的人最终分数更高。在保证正确性的基础上,学有余力再去提高性能,应当才是我们程序设计的原则。















浙公网安备 33010602011771号