第一单元oo感想
一.作业思路
三次作业整体思路大致相同,第一步处理表达式,第二步求导,第三步数据优化,第四步输出数据
前两次作业
第一次作业较为简单,只需要考虑常数因子以及幂函数因子即可,对于每一个项构造一个对象,对象中两个成员变量分别是幂函数系数和幂函数指数,最后进行求导即可。
第二次作业多了简单正余弦函数,对于每一个项构造对象,每一个都可以化简为常数*幂函数*正弦函数*余弦函数,对象成员变量四个,分别是系数,幂函数指数,正弦函数指数,余弦函数指数,最后利用乘法规则求导即可。第二次化简表达式主要依据
sin(x)^2+cos(x)^2=1公式化简,通过一层循环,只要满足x指数相等,正余弦函数指数互相差2,或者单独一个指数差2,系数不需要相等,根据对应情况化简即可。
对于前两次作业判断正误时,均可以根据表达式规律构造大正则直接匹配,然后每项单独进行提取构造对象。唯一存在的问题就是使用正则表达式可能出现爆栈问题,此时将正则表达式匹配模式由贪心模式变为独占模式即可,因为使用规律匹配不需要回溯。
第三次作业
第三次作业难度相比于前两次大大增加,也需要真正使用到面向对象的相关知识继承和接口。通过接口可以将不同的对象放到同一个接口数组中,施行相同的操作。构建常数因子对象,幂函数因子对象,正余弦函数因子对象,以及嵌套因子和表达式因子对象。
1.处理表达式
我没有采取助教推荐的构建表达式树,我运用到了栈和表达式求值的思想。构造符号栈和表达式栈,首先遍历:读到左括号循环匹配到右括号,将整体创建嵌套因子对象,读到s\c判断是否嵌套构造三角函数对象或嵌套因子对象,常数构造常数因子对象,x构造幂函数因子对象。读到+,-,扔进符号栈。
样例:sin(x)*x*(cos(x)+x)+2
分别构造sin(x),x,(cos(x)+x)进入对象栈,符号栈* * +,读到+就要出栈,读到n个*,对象栈就出n+1个对象,分别求导即可,对于嵌套和表达式因子的求导使用递归,最后输出结果即可。
2.判断表达式正误
除了用递归下降来判断表达式的正误,还有一个方法。首先明确,表达式由项加减构成,项由因子通过乘法相连,与第二次相比多了一个嵌套因子和表达式因子,表达式由因子构成,而因子又可以通过表达式两端套括号构成,嵌套因子又可以由表达式因子构成,所以这就好比是一个你中有我我中有你的问题,我的解决方法就是使用一个循环进行替换,首先空格特判;然后判断幂不超过10000;将常数因子、幂函数因子、三角函数因子归为简单因子,将形如 (简单因子构成的表达式) 变为x,但是这样有个问题,sin(x)本来正确这样会替换成错误,所以还要把形如 sin(简单因子)、cos(简单因子) 也替换成x,而且优先级高于括号套表达式,这样循环往复第三次作业的表达式就会变为第二次作业的表达式,再用第二次的方法判断正确性即可,但是每次替换之前需要判断是否出现 (表达式) 后跟着幂指数,如果有停止替换输出WF即可。
样例:sin((x+cos((sin((x^2-cos(x)^3+sin(x)^4))+cos((sin(x)-x))))))
第一次替换(x^2-cos(x)^3+sin(x)^4)、(sin(x)-x)变为x,结果sin((x+cos((sin(x)+cos(x)))));
第二次替换(sin(x)+cos(x))为x,结果sin((x+cos(x)));
第三次替换(x+cos(x))为x,结果sin(x);
第四次替换sin(x)为x,结果为x,符合第二次表达式,不需要输出WF,接着求导即可。
缺点
这样的做法过于面向过程,而且功能不宜扩展。
类图
度量分析
二.BUG产生与修复
1.个人BUG问题
I.空格特判没有考虑全所有情况
II.正则表达式少写了转义符\或者少了+
这两个BUG只有通过构造大量的测试样例才可以发现。
III.第三次强测结果出现了两个TIE
原因:在一个判断语句条件中调用递归的结果,后期再次使用递归相当一次递归时就使用了两次递归,修改时直接将递归的结果放在一个中间变量,后期直接使用该变量就不再出现TIE了,通过这种问题可以积累经验。
2.互测他人BUG问题
I.在自己编写代码时一定会出一些复杂数据不易处理的情况,这些数据在互测时比较有用。
II.读他人代码,主要以输入处理和正则表达式为主,这些地方比较容易出现问题。
III.数据化简时候BUG也比较多,需要深入分析他人代码,盲狙效率很低。
三.个人感想
1.作业完成过程
对于每一次作业,一定要提前构思好结构,而不是直接写代码,好的结构可以大大简化后期的工作。当进行代码的编写时,不用提前考虑好所有代码的细节,由于面向对象的特性,我们可以先写一些简单的类,在类中写好对应的方法,后期直接引用提前写好的对象,最后把最难的部分完成即可。