OO第一单元总结
第一次作业
一、程序结构分析
第一次作业只有幂函数和常数的组合
第一次作业只使用MainClass,Term和Poly三个类
Term类
有coef和degree两个属性,分别是幂函数的系数和指数
Term(String s)是构造方法
getCoef()和getDegree()用来获取该项的系数指数。
Poly类
属性只有map,以degree为key,以coef为value。
其中方法add()添加Term对象
derivation()对map中的每一项求导并以字符串输出。
第一次作业整体思路:
通过Term类实现把每一项化简合并为系数,x,幂的格式,同时实现了1次幂,系数为1此类的项的化简
在Poly类的构造方法里 通过hashmap的性质,实现整个表达式的化简,即合并同类项
最后调用Poly类的derivation()方法实现对化简后整个表达式的求导
第一次作业在Term类尝试使用面向对象的思想,但Poly类本质上仍是面向过程。因此在第二次作业中不得不进行重构。
复杂度分析
二、遇到的bug
强测和互测都是同质错误,由于试图追求表达式简洁,忽略了*1省略1时的乘号出错,强测翻车。
hack到的bug:
1.正则表达式爆栈
2.根据形式化表达,表达式、项、带符号整数前最多可出现三个符号,直接使用replaceAll()替换两个符号导致错误
三、心得
通过中测不是目的,一定要考虑到每种情况构造样例自己测试。第一次作业出现的bug并非是难以构想的极端情况,只是自己测试不够认真。
第二次作业
第二次作业引入了三角函数和表达式因子(即嵌套因子)
一、程序结构分析
按层次创建类有:Poly、Term、Factor。
其中Factor作为父类,是一个抽象类,其中有抽象方法toString(),derivation()。
Factor的子类有Constant,Cos,Sin,Power,Poly,分别重写了抽象方法toString(),derivation()。
Term中因子的关系是乘法关系,因此求导法则即乘法求导法则,因此创建了Multi类
Multi类中有方法derivation(),但返回值是String,为后续优化带来很大不便
整体思路:
Expression类简单粗暴对表达式进行了空格全部删除,多个符号替换(根据形式化表达最多连续出现三个符号)
Poly类的构造方法通过传入表达式,先拆项。拆项过程中需要注意的是,判断是否是括号外的有效加减号,(有效即加减号前不能有“^”和“*”)
拆项后进入Term类拆成因子,并使用了工厂模式,对对象批量进行初始化
求导的过程也是poly类求导调用term类,term类调用factor的各个子类的求导方式
复杂度分析
二、遇到的bug
强测和互测中都没有被发现bug
hack到的bug:
常数求导无返回值
三、心得
为了首先保证正确性,并没有进行太多优化,性能分比较低。
在研讨课上听到同学分享的方法,可以使用数据结构中的后缀表达式,进行拆括号的优化。
第一次到第二次的跨度是第一单元中最大的。初步接触面向对象,将思维由面向过程转向面向对象的过程是痛苦而挣扎的,但是在第二次作业的时候就意识到,面向对象让我的代码可移植性变强了,面对一些新增的需求只需要对几个类进行微调就可以实现相应的功能。
第三次作业
第三次作业实现了三角函数内部因子可嵌套,同时增加了对WF的判断
在第二次作业时,就做好了三角函数内嵌套的准备,因此这次合法表达式的求导过程比较轻松,没有太多的改动
一、程序结构分析
在第二次作业的基础上 ,为Cos,Sin类引入了factor属性,更新了求导方法
试图对求导结果进行优化,使Term类的better()方法返回Hashmap
但优化程度有限,性能依然较弱
于我而言,第三次作业的难点在于WF的判断,尤其是对空格是否合法的判断,因此引入了Expression类判断部分表达式不合法的情况
Expression类中仅能解决数字之间,三角函数关键字之间的非法空格,更加复杂的情况在于判断符号与数字之间的符号是否合法。
复杂度分析
二、遇到的bug
在两处WF判断时出现问题,在强测中挂掉两个点,互测中没有被hack,也没有成功hack别人
表达式因子的判断:最后一个字符需要判断")"
cos(),sin()内只能出现五种因子中的一种
互测过程中发现room内同学也有WF判断有问题,但无法hack
三、心得
面向对象的思维让第二次到第三次的过渡轻松了很多。
反思
- 三次作业的难度梯度上升,其中第一次到第二次的跨度更大一些,经历了一次重构,因此更能深刻体会面向对象的可重用性
- 在讨论区多次见到“递归下降”这一玄妙的方法,在研讨课也有同学分享过,但目前仍没能很好理解。