BUAAOO-第一单元总结-多项式求导

#面向对象第一单元总结与反思
##1 第一次作业
###题目描述
第一次作业是对由幂函数和常数构成的项进行简单线性组合后得到简单多项式导函数的求解。
###思路与解题历程
在写第一次作业之前,我是属于毫无头绪的那一类。直到周六晚上,我才确定了自己的思路。与大多数人在第一次作业使用正则表达式不同,我第一次采用了上学期学过的有限状态机对读入的表达式进行求解,最小基元是项,从而将表达式的求导转化为各个项的求导的线性组合。
第一次作业我分为了三个类,MainClass、Expression和Term。由于使用有限状态机处理时采用了switch语句,导致Expression的构造函数方法过长。
###基于度量分析程序结构
image
第一次作业的构造较为简单,其类图如上,其中各类的功能在思路中已经详述,此处不再赘述。

从复杂度度量可以很明显的看出,Expression的构造函数的复杂度很高,这是由于未对有限状态机中相同出口进行合并而造成的,事实上,在第二次作业中,这个类的复杂度变得更高了。
###程序Bug分析
由于时间原因与自身实力的关系,自己的程序并没有通过全部的中测点,因此没有进入互测,以下互测Bug是和其他同学讨论时对他们的程序进行测试发现的Bug。
####自身Bug
第一次作业没有通过中测的原因是在常数的求导中,我的Term项返回了空串"",而Expression并未对这一特殊情况进行处理;另外一个Bug是因为有限状态机的出口过多,我一开始是利用出现在'X'或数字后的加减号来分割项的,但是表达式的末尾也天然具有分割能力,这一点我没有考虑到。在修改了这两个地方后,我用python随机生成的数据进行了4000多组的测试,程序均运行正常
####互测Bug
在对同学的程序进行测试的时候,主要发现的Bug种类有:对于复杂度较高的表达式,采用正则表达式提取时运行速度会很慢,或会发生爆栈现象。
###程序优缺点
####优点
采用有限状态机的优点是拓展性较强,事实上有限状态机的方法就等价于递归下降的方法,后期修改时较为方便;另一个优点是相较于正则表达式的提取,程序运行速度快。
####缺点
本次作业的缺点并不是采用有限状态机方法的缺点,而是自己在构造程序时产生的缺点。
第一个问题是对JAVA的语法等不够熟悉,造成写出的程序非常面向过程;
第二个问题是在状态机的处理上过于冗杂,没有对相同的出口进行合并,一个方法已经达到了200行,导致后期进行修改时无从下手。
第三个缺点是在基元的选择上,由于最小基元是项而不是因子,因此在需要处理的最小基元是因子时,就需要大规模的重构,这在第三次作业中体现的颇深。
##2 第二次作业
###题目描述
第二次作业在第一次作业的基础上增加了表达式的括号嵌套与三角函数sin(x)和cos(x)的求导。
###思路与解题历程
与大多数人不同,我的第二次作业写的很顺利,没有大规模的重构,而是在第一次的破烂上面修修补补。第一次作业利用有限状态机可以很容易处理x变为sin(x)或cos(x)的情况,第二次我主要添加了两个类,NewTerm和NewExpression。
这次作业的主要思路是求导自下而上,对于不含括号的表达式,交给Expression处理,而Expression求导是基于Term的返回值进行线性组合,这是递归调用的递归基;对于一般的含括号嵌套的表达式,则由NewTerm和NewExpression完成以下操作:
1、NewExpression读取表达式,每当读取到一个含括号的项,将其交给NewTerm求导,并从表达式中删除该段;剩余的不含括号的表达式,则交给Expression完成求导操作。
2、NewTerm完成表达式的划分:将含有括号的项划分为n个表达式的乘积,对该项进行n2次遍历,完成求导;括号内表达式的求导则交给NewExpression处理;
这样两个类递归调用,最终完成表达式的求导。
###基于度量分析程序结构

第二次作业是基于第一次作业的基础上进行了微小的改动,自下而上的求导方法在本类图中尤为明显,这次作业新增加的类也尽可能做到短而精练,其复杂度分析如下:
image
可以看出,由于边界情况的特殊处理没有完成的很好,几个求导的方法复杂度较高。
###程序Bug分析
第二次作业完成的匆匆忙忙,在交上去的时候我就已经发现了几个Bug,但是已经没有精力进行修复了,因此最终完成的结果并不好。
####自身Bug
1、在NewExpression删除含括号的项时,数组越界;
2、在NewTerm将含括号的每一个表达式分发给NewExpression时未考虑边界情况
####互测Bug
1、形如((((((((((((((x)+1)))))))))))))之类嵌套层数很多的式子;
##3 第三次作业
###题目描述
第三次作业在第二次作业的基础上增加了sin和cos的嵌套。
###思路与解题历程
前文已经提到,求导时我选取的最小基元是项,即axnsin(x)pcos(x)q,此次sin(x)和cos(x)均存在嵌套的情况下,只能重构Term类。我的一个思路是在Term中改变sin和cos的数据存储方式,并重写求导方法,将sin和cos括号中的求导交给NewExpression完成,其他不变;同时增加checkFormat类,在开始利用简单的正则表达式进行错误格式检查;但是由于时间关系与自身能力的原因,仅仅完成了CheckFormat。
###基于度量分析程序结构
image
第三次作业有较大的重构,尽管没有完全完成,但已经可以明显看出面向对象与自下而上的结构,各个类的功能同第二次作业,其方法复杂度也均有一定的减小,仅仅增加了CheckFormat一个类。
由于类中尚有不完善的处理,因此复杂度度量仅针对各个类进行。
image
可以看出,尽管进行了一定的重构,但是并未对某些相同出口进行合并,Term的复杂度依然较高。
###程序Bug分析
第三次作业的Bug(或者说是未竟之志)可以说是很典型的,就和博客园这次的事故一样,前期的准备不足,导致后期的开发迭代过程十分艰难,依据我的思路继续,或许可以完成这次作业,但是其中繁琐的工作量让我望而生畏。
##感想与收获
最大的收获可能是心态方面吧,当然关于Java的操作也熟练了很多。经历了第一单元的磨练之后,我最大的体会是良好的开端可以省下很多不必要的重构,当然,实际开发过程中是很难一下弄清楚所有的需求的,因此良好的设计模式是必须的;之前研讨课介绍设计模式的同学给我留下了深刻的印象。
另外一个体会是评测机很重要,自动化的测试工具可以减轻90%以上的debug负担,同时可以尽情hack别人,第二次作业我被hack了60多个错误,对自动测试工具的威力体会颇深。
第三个体会是在创建项目时,应尽可能选择其最小因子作为基元,降低程序的耦合性,尽管有时选择较大的模块作为基元同样可行,甚至更为简便,但是一旦遇到需要对基元进行修改的情况,就需要全盘重构,这种代价是很大的。

posted @ 2021-03-30 00:38  Stanlei  阅读(124)  评论(1编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css // // // // // //