2019_BUAAOO_第一单元总结

 

前言

  校历第五周,面向对象程序设计课程的第一单元告一段落。在第一单元的作业中,我们围绕着“表达式求导”的题目展开,从第一次作业的最简单的多项式求导,到第二次作业增加简单的三角函数求导,再到第三次作业增加复合函数嵌套求导……难度是在不断增加的,但是如果从一开始的第一次作业的设计就有着清晰的层次和逻辑,为后面的两次作业留下扩展的空间,那么在后续的作业中可谓是事半功倍。但是想必大多数人拿到新作业都是要对代码进行重构的,包括我本人。

  完成第一单元的三次作业,回过头看,还是有很多值得分析和思考的地方的。这篇博客就将对本人在这三次作业中的代码进行分析,并简单给出自己的做题思路,若有不当之处,还请大家及时指出。

一、分析程序结构

  1. 第一次作业(简单多项式求导)

  在做第一次作业时,我还完全不理解面向对象是什么(虽然现在也只是一知半解……)。但是为了避免“一main到底”的情况出现,我还是象征性的建了一个类。

  在Exp这个类中,有很多对表达式进行操作的方法,如判断合法,split分成一项一项,求导运算等等。以下是第一次作业的复杂度和行数统计。

  由此得出在Exp.calculate()方法中的复杂度还是比较高的,也是后续可以优化的一个方面。在本次作业中,最主要的思路是用每一项的正则表达式去匹配,匹配到之后用substring将匹配的字符串取出并对其用 * 和 ^ 进行split分割,然后用正常的多项式求导公式计算,并分情况输出。化简也比较简单,只需要考虑指数是否相同,若相同将系数相加即可。若想再提高性能分,可以将系数为正的项提到第一项(若有正项)。

  2. 第二次作业(三角函数)

  在做第二次作业的时候简单分析了一下,和第一次作业没有什么太大的不同,也就是新增添了三角函数。只需要改一下正则表达式,增添对sin(x)和cos(x)(可以带指数)的判断,然后设置四个Arraylist,每一个位置分别对应存储该项的常数项系数、幂函数指数、sin的指数、cos的指数。然后用高中所学的求导方法对一般情况(a*x^b*sin(x)^c*cos(x)^d)进行求导,求出通式。化简的话,合并同类项与第一次作业类似,并删除常数项系数 a=0 的项。

  化简的话,我主要针对可以把 (sin(x)^2+cos(x)^2) 提出来的情况进行化简,也是求出通式并进行化简。由于做了这一项操作,最后强测的性能分还不错(虽然互测被找到了化简bug……)。

  由于没有对第一次作业进行完全的重构,所以第二次作业是在第一次作业的基础上进行修改,也有点“一main到底”的意思。

  下面是复杂度和行数统计。

  由于化简部分需要考虑的情况很多,因为是对两个项进行操作,所以写了一个双重循环,复杂度比较高。

  3. 第三次作业

  第三次作业难度剧增,由于复合函数的引入,让我们不得不采用递归的思路,并且也要应用继承和接口,使我们的代码更具有层次化,可读性也会增强。

  在思考如何判断输入合法时,我的思路是这样的:

  判断输入表达式合法 --> 判断每一项合法 --> 判断每一个因子合法

  在本题中,我把因子分成了三类。第一类是常规因子(Normal Factor):带符号整数与幂函数;第二类是嵌套因子(Nest Factor),由于因子可以嵌套到三角函数中,所以最基本的三角函数也可以看成嵌套因子的一种;第三类是本次作业新增的表达式因子(Expression Factor),一个表达式外套了一层括号。

  接着上述流程,判断每一个因子合法 -->

  • 若是常规因子,则正常判断并返回。
  • 若是嵌套因子,则嵌套的因子又可以分成上述三类,这时就要判断因子是哪一类,再次进入判断因子合法的阶段,判断三个因子的方法(函数)都要调用一遍,包括调用自身,也就是递归的思想。
  • 若是表达式因子,则要调用最开始的“判断输入表达式合法”的方法(函数)。

  这种递归是十分容易理解且操作起来比较方便的,缺点就是有的时候可能会对递归结构的理解思路突然不清晰,容易写错代码;并且存储成树状结构也会有点困难,很难直观理解;也不太容易化简(其实遍历子结点理论可行)。

  以下是本次作业的具体层次,所有的类都是因子(Factor)的子类,其中Expression是用于处理数据的一个类。


  在求导过程中,我会先判断因子与因子之间的关系(对我自己存的树的结构进行完完全全的刨析,由于树就比较乱,所以这部十分麻烦),相乘?或是嵌套?如果判断出来是项和项的话,就直接相加输出就好了。对于本思路的化简,目前没有一个特别好的方法,我的代码只是对 1* ,0+,这一类可有可无的小尾巴进行删除。

  由于在判断嵌套函数、求导、打印输出都使用了递归思想,所以复杂度较高。

二、分析自己程序的bug

  1. 第一次作业

  在第一次作业的互测阶段中,我被找出的bug为,如 x-x , 0*x^n 形式的,求导结果为0的情况,我的程序输出无输出。

  针对这个bug的修复,我会先对已有的存放常数项系数的Arraylist进行遍历判断,如果均为0,则输出也为0。

  2. 第二次作业

  在第二次作业的互测阶段,我的bug出现在化简 sin(x)^4 - cos(x)^4 这类的情况,我没有判断两项的常数项系数和幂函数指数要分别相等,导致化简错误。

  针对该bug的修复,仅需要在化简前增添if判断条件。

  3. 第三次作业

  在第三次作业的互测阶段,我对第一项前可以多添加的负号没做处理,导致如同 -x+x 的情况会出错。

  针对该bug的修复,仅需要在第一项前判断符号为负时,在表达式树中的该层增添一个 -1 的因子与第一项相乘。

三、互测阶段的策略

  在互测阶段,我首先是对一些边界条件进行了测试。比如,长度很大的数据(爆栈),特殊字符如 \f\v 等,或者一个常数,等等。

  在第一次和第二次的作业中都可以采用一个自动生成测试数据的文件,并采用.bat脚本和.py的程序对房间内的其余人的代码运行和比对。

  在第三次的作业中,生成测试数据变得有些困难,所以自己在本地输入一些嵌套比较多,比较复杂,每一个因子都带有指数(带符号)的数据。

  在前两次的作业中,我会简单的看一下房间内其余人的正则表达式,和代码的思路,如果发现可以错误就输入数据测试;但是由于第三次的作业代码量很大,思路也很复杂,所以我并没有分析其余人的代码,通过代码找bug,而是输入了一些自己在做作业时会犯一些错误的数据。

四、Applying Creational Pattern

  在前两次的作业中,创建对象都是通过简单的自定义构造函数模式,容易理解上手。

  在第三次的作业中,为了处理复杂的逻辑关系,我在判断表达式合法时,就将每一个因子(项)以工厂模式新建一个对象。在函数内部显式地创建了对象,并将该对象作为函数的返回值,插入到表达式树中的一个节点,便于最后的求导运算。

转载于:https://www.cnblogs.com/zja1999/p/10597851.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值