第一次作业要求:
实现简单的多项式求导,包含且仅包含x的幂,其中第一项可以多包含一个加号。
第一次作业思路分析:
回想起来,第一次作业还是相当简单的。
在这次作业中我使用了两个类
-
Item --> 代表多项式中的一个项
-
Poly --> 以Item为数组元素的可变数组
在使用类的时候初步注意了java的面向对象特性,Poly对Item的操作均是方法调用,虽说不明显,但是已经开始在OO的路上开始前进了。
正则表达式
正则表达式如果大量使用嵌套的括号以及*容易造成灾难性回溯。为此,我使用了分次进行正则匹配,先统一所有项的格式,再排除一部分空格造成的错误,再进行正则匹配。压力测试能接受780+项 ‘+x’ 不爆栈
第一次作业工程化分析
这次的作业最重点的是表达式正确与否的判断,以及构造多项式对象。
由于我个人原因还加入了比较复杂的化简方法
其中化简使用了重新生成多项式对象然后tostring的办法,总体而言,对于各种情况考虑的比较到位。但是忘记将负项提到了前面,因此丢了一点点分。
第一次的工程化做的不是很好,check里面有些功能比较独立本应分开,但对于这种不复杂的项目大约也是够的。
测评解析
强测的优化做的不够,得到了三次作业的最高分99.75。互测时一开始没有被hack,后来被空格hack了3次。原因是没有判断纯空格的情况。思虑不够周全,主要是没有先测试后写代码。
第二次OO作业
作业要求:
比上一次多添加了一个三角函数,同样有幂的关系,这次乘法项变得复杂了起来,也有了更大的优化空间。
作业思路:
首先是用加减号分割一次,成为item对象,再用*分割,成为factor项。
对于factor的处理,我采用的是三个固定项的形式,这样对化简比较有利,一个item对象至多只有四项(常数因子成为item的属性)。
难点在于如何判定正确,借鉴上次互测时看到的大佬的思路,使用|来分割正则,有效避免回溯。因此这次我直接使用大正则,在字符长度范围内不会爆栈。
第二次作业工程化分析:
先从图来说,明显还是check函数最臃肿。这次我已经动了拆解check的念头,但是因为时间不太够(加上忘记打开checkstyle)最终还是放任自流了。
对这次的工程我比较满意。(bug很多我是知道的)当然还是没有用到很多OO的面向对象思想,但是对于我这个脑子总是混乱的人来说,这次的代码比较简洁并且功能分开,清楚,命名也一眼能懂。后来写第三次作业10分钟就全部回想起来。
有一点比较遗憾的是没有使用接口,虽然依然不太明白接口能带来什么好处,或者说有什么大家一起共用的代码,但是写了总是好的吧?
互测/测试
这次的强测让我非常遗憾,只有30+,勉勉强强能进入互测而已。其实这次的代码我自己还是比较喜欢的。但是时间又不够用了。回想起来时间主要花在了check上:
首先反向排除空格错误,再合并空格,再统一一下x前面有+-的情况,接着直接一个大正则。
-
再一次没有运用先测试后写代码是因为写了测试用例之后也不知道如何下手。
-
不知道如何下手是因为没有成功地把错误格式分类。
最好是能有一个比较容易扩展的总体思路,然后根据各个小情况,将功能逐步合并。
-
若能够先测试后编写,穷举错误格式将会是风险较高收获较大的方法。
-
编写错误格式有困难是因为分给研究指导书的时间不够,因为不够重视。
-
下次的改进办法是再写一份自己理解的指导书和测试用例
互测阶段我可能是不够自信,(一种奇怪的恶性循环)所以我没有怎么测试,也没有怎么修复bug,我用几乎所有的时间去写了自动化测试脚本,本来想要用到第三次作业中.....然鹅发生了惨案。
我被hack了19次,然后因为身体原因加上不够重视,一次也没有修复,也许是个不及格的分数吧。这不仅是学习上的问题,是我不会分配时间,不能高效的集中注意力决定的。
第三次作业
作业要求:
比较前两次作业,这次多了嵌套的规则。主要表现在,因子可以带很多层括号,干扰判断拉低性能;
作业思路:
消灭嵌套,将括号内部的统统换成y,并提前排除y的存在。留下y被替换的部分,当做数组继续向下传递。被替换掉的部分不判断正确性,留给下一层判断。
每一层都作为一个poly多项式对象,poly由item组成,item由factor组成,factor延续二次作业中的固定四项,并添加嵌套型子类,三角嵌套和普通嵌套项。
在每一种项里实现求导和check。可抛出异常,处理异常时直接exit system(0)
代码工程化分析:
(图中的X我并没有实现)
这个代码的架构比较松散。而且总体也非常丑陋
各个类实现的deri都相当蹩脚。
主要原因是我将优化和deri还有tostring放在了一起。目前分析可以优化的办法:
-
求导的结果,除了因子factor(包括递归)以外,其他的类求导不可以返回string
-
实现方法的提取,比如定义二维数组保存不变项。
-
tostring 方式尽可能的优化,实现0-1的判断,空串的填充,0,1分开判断,则空串有明确的意义,就更好填充
这次实现嵌套子类时也显得非常低龄化,更好的实现办法是将常数,x,cos(x),sin(x),嵌套三角,普通嵌套分开。实现求导接口。这样整体架构必然清晰。
附:为什么求导接口看上去一点用都没有还要写?
我真的一点也不想写,但是查阅了资料后发现,它就像是一个招牌,当程序规模变大时你能清楚地知道它有什么功能。
这次的check我写的也比较丑陋,原因是拆分功能时发现耦合度比较高,只能一遍遍地实现已实现的东西。如果还有机会,我会:
-
将check分为功能明确的几段。比如,空格段,+-号处理段,大正则匹配段。
-
仅在poly处实现检查,只在检查指数大小的地方多加exit(0),其他只管计算。
失败经验&大佬代码分析
这次我没能按时完成作业,截止之前,提交次数为0 。
血的教训:
-
动笔得晚
-
不相信自己的思路,导致完全重构*1
-
没有动键盘之前胸有成竹,完全的写Bug,写完之后再de就发现自己根本不记得一些小细节
-
提前充分考虑遇到的可能情况,先写测试集再测试
-
对于写代码需要用到的知识点,必须先学会再做题,弄懂继承的用法竟花费了最多时间
-
磨刀不误砍柴工,越是一开始就一丝不苟,反而会写的越快,否则,写的越快错的越快
大佬代码
我借助室友看了一下优化相当厉害的大佬的代码。好处学到的不是很多,我能说一下缺点吗?
-
命名不规范,同事两行泪
-
优化是针对极限情况专门做了些优化,且分布较散,想来维护不是很简单
-
窃以为规模比较小时,还是不用接口啥的更方便emmmmm但是我下次必须用,看起来真的难受
-
缺少注释
优点:
-
-
列出了关系项,加和乘,解决了我不知道怎么处理关系项的疑惑。
-
方法提取的较好,没有特别长的方法
后记
不管怎么样,还是要给自己打个气!
我不服气自己这么菜
不能相信别人所谓的不想学,不能相信自己做不到。