OO1-3次课下作业总结
OO第一单元总结
整体总结
OO课程的第一单元作业主题是第1到3次作业,内容是尽可能多的拆括号并化简表达式。我在假期里并没有预习任何面向对象的知识,也没有学习git等工具的使用,更没有配置IDEA、eclipse等编辑器的Java环境,在刚开学就近乎于期末的高压下,我这三周过的很痛苦,但是也收获了非常多的知识和面向对象编程的思想和方法。在第一周,我主要是进行配置环境,学习git的使用,pre2前三个task的学习,但是由于我对时间规划的不合理,我并没有及时完成第一周的作业,中测有3个测试点没有过,而且用了很多的static函数,更像是在完成一个面向过程的编程任务。在第二周,我在同学的帮助下,理解了递归下降的拆括号方法,还在强生同学的帮助下,认识了Hashmap容器,成为了我第二次作业基本项的一部分。第二周是最痛苦的,因为我第一周的作业基本上是面向过程,所以我第二周必须要重构代码,在递归下降的返回值问题上,我思考了很久,最后也是在同学的帮助下,把返回改成void类型,对我递归下降的思路帮助很大。在第一周和第二周,我把pre2和pre3前四个task做完了,学习了正则表达式等知识,在我重构代码的过程中,我感受到了面向对象编程的魅力所在——不需要重复造轮子,大大减少了代码量。由于我在第二周对代码进行了重构,并且支持多层括号的拆分,在第三周的作业中我需要改动的部分比较少,因此对我来说第三周是比较轻松的。在对自定义函数和三角函数内部进行迭代之后,代码总体上可以正常运行。总结一下,OO课程在第一个月就让我压力报表,但是我学到的知识确实值得我付出的努力和艰辛。
个人架构分析
我采用了递归下降的方法,一个Expr由多个Term加减得到,一个Term由多个Expr相乘得到,经过自定义函数替换、求和函数替换、去空白符、拆乘方、去前导零、化简连续加减等预处理之后,表达式作为一个Expr传入,把它拆分成多个Term相加。此时需要判断Term是否为最小项(常数、x、sin()、cos()),如果不是最小项,则需要把这个Term拆分成多个Expr相乘;如果是最小项,则需要把这个Term转化为一个基本项,储存在Term的Variables属性里。每一个Expr和Term都有一个ArrayList
对此设计我们也可以进行一些优化,比如我们可以在把最终的Variables翻译成表达式之前进行合并同类项操作,这样可以缩短表达式长度。在第三次作业中题目要求化简三角函数括号里的表达式因子,我们可以遍历得到的表达式,把所有三角函数内部的表达式因子以同样的方法进行化简。我很还可以利用sin(x)2+cos(x)2=1的性质,把所有的cos(x)2转化成1-sin()2,这样也有利于化简。同理也可以使用二倍角公式等三角函数知识进行化简,在这里不再赘述。化简的方法有很多,只要肯花时间一定能拿到很高的性能分。在我的代码中仅仅做到了合并同类项这一步。
类图描述
在实现过程中,我使用Factor接口作为Term,Expr和Variable这三个大类的统一接口,目的是可以用一个ArrayList将不同类的数据集中起来,方便处理。Custom类是用来替换自定义函数的类。我处理sum函数的方式是在Mainclass里用static函数处理。
优点:类数量比较少,思路更加清晰。
缺点:使用大量的static函数,整体结构不够精巧,面向过程痕迹比较重。
度量分析
Complexity metrics | ||||
---|---|---|---|---|
Method | CogC | ev(G) | iv(G) | v(G) |
Custom.Custom(String) | 1 | 1 | 2 | 2 |
Custom.getName() | 0 | 1 | 1 | 1 |
Custom.getValue() | 0 | 1 | 1 | 1 |
Custom.getVars() | 0 | 1 | 1 | 1 |
Expr.Expr(String) | 0 | 1 | 1 | 1 |
Expr.calVariables() | 1 | 1 | 2 | 2 |
Expr.findNextAddOrSub(String) | 9 | 3 | 7 | 9 |
Expr.getFinalvalue() | 41 | 10 | 14 | 17 |
Expr.getTerms() | 11 | 1 | 9 | 11 |
Expr.getVariables() | 0 | 1 | 1 | 1 |
Expr.merge(ArrayList |
7 | 1 | 6 | 6 |
Expr.removeAddOrSub(String) | 13 | 1 | 8 | 11 |
Mainclass.calfinaladdstr(String, int) | 7 | 1 | 1 | 4 |
Mainclass.findNextComma(String) | 6 | 5 | 5 | 6 |
Mainclass.findbracket(String) | 6 | 3 | 3 | 5 |
Mainclass.findinversebracket(String) | 6 | 3 | 3 | 5 |
Mainclass.getParas(String) | 6 | 1 | 6 | 6 |
Mainclass.main(String[]) | 1 | 1 | 2 | 2 |
Mainclass.needcontinue(String, int) | 7 | 2 | 7 | 8 |
Mainclass.pre1(String) | 2 | 1 | 3 | 3 |
Mainclass.pre2(String) | 26 | 6 | 11 | 11 |
Mainclass.replaceAllCustoms(String, ArrayList |
1 | 1 | 2 | 2 |
Mainclass.replaceCustom(String, ArrayList |
42 | 8 | 14 | 14 |
Mainclass.replaceSum(String) | 17 | 1 | 6 | 8 |
Mainclass.replacetrig(String) | 7 | 3 | 3 | 3 |
Term.Term(String) | 2 | 1 | 2 | 3 |
Term.calVariables() | 7 | 1 | 5 | 5 |
Term.findNextMulti(String) | 7 | 3 | 4 | 6 |
Term.findinversebracket(String) | 6 | 3 | 3 | 5 |
Term.getExpr() | 0 | 1 | 1 | 1 |
Term.getExprs() | 11 | 1 | 6 | 7 |
Term.getFinalvalue() | 39 | 10 | 12 | 15 |
Term.getSignal() | 0 | 1 | 1 | 1 |
Term.getVariable() | 14 | 1 | 9 | 10 |
Term.getVariables() | 0 | 1 | 1 | 1 |
Term.isMininum() | 6 | 4 | 5 | 6 |
Term.merge(ArrayList |
7 | 1 | 6 | 6 |
Term.multiVariable(Variable, Variable) | 4 | 1 | 5 | 5 |
Term.multiVariables(ArrayList |
3 | 1 | 3 | 3 |
Term.setExpr(String) | 0 | 1 | 1 | 1 |
Term.setSignal(boolean) | 0 | 1 | 1 | 1 |
Variable.addcos(String, int) | 2 | 1 | 2 | 2 |
Variable.addsin(String, int) | 2 | 1 | 2 | 2 |
Variable.getCoefficient() | 0 | 1 | 1 | 1 |
Variable.getCoss() | 0 | 1 | 1 | 1 |
Variable.getExponent() | 0 | 1 | 1 | 1 |
Variable.getSins() | 0 | 1 | 1 | 1 |
Variable.setCoefficient(BigInteger) | 0 | 1 | 1 | 1 |
Variable.setCoss(HashMap<String, Integer>) | 0 | 1 | 1 | 1 |
Variable.setExponent(int) | 0 | 1 | 1 | 1 |
Variable.setSins(HashMap<String, Integer>) | 0 | 1 | 1 | 1 |
在这里我们可以看见,Cogc值比较高的方法集中在对表达式的预处理和Variables的翻译过程,这两个部分都是进行了字符串和类的形式转换,所需工作量比较大。
Class | OCavg | OCmax | WMC |
---|---|---|---|
Custom | 1.25 | 2 | 5 |
Expr | 5.25 | 16 | 42 |
Mainclass | 4.85 | 12 | 63 |
Term | 4.25 | 15 | 68 |
Variable | 1.2 | 2 | 12 |
个人bug总结
第一次作业:由于我的第一次作业没有通过中测,出现的bug比较多,在这里我总结出比较严重的一个bug——系数应该使用BigInteger类型存储,我使用的是int类型,导致第七个数据点溢出。
第二次作业:由于我在第二次作业重构了代码,因此出现的bug也比较多。一、在Expr的Variables翻译成表达式字符串时,若某一项系数为0,我会在原有基础上补充一个空字符串。但是我在判断首位是否为正好时,使用了indexof(0),导致空串数据越界。这个bug出现频率很高,被很多人hack到了。二、在提取项中间的正负号时,没有考虑到三角函数内的正负号不应该被提取,把sin(-1)提取成了-1*sin(1),虽然这种情况下是正确的,但是遇到平方或者cos()就会出错。
第三次作业:由于第三次作业中的自定义函数和求和函数更加复杂,但是我并没有更新这两部分的替换机制,出现了两个bug。一、sum函数中替换i应该加上括号,如sum(i, -1, 1, sin(i**2))。二、自定义函数出现的x被替换的问题。比如
2
f(x, y) = x**2 + (y + 2)**2
g(z, x) = cos(z) + 8*x
f(f(sin(x), 1), g(2*x, f(x, 2)))
//以下是bug出现过程
在计算g(2*x, f(x, 2))时,把cos(z) + 8*x中所有z换成2*x,转化成
cos(2*x) + 8*x
再把cos(2*x) + 8*x中所有x转化为f(x, 2),转化成
cos(2*f(x, 2)) + 8*f(x, 2)
很明显不应该把cos(2*x)中的x替换成f(x, 2)
学习心得
首先,我在这一个月深刻意识到了假期预习的重要性。在第一周的周二,我还在配置IDEA的Java环境,学习git的使用;周三我完成了pre2task1;周四我完成了pre2task2;周五上午我完成了pre2task3,晚上才开始写作业。第一周的进度非常赶,导致我最后差2个小时完成作业。这第一周的生活给了我深刻的教训,一定要在假期预习。其次,我认为OO课程组提供的指导书和廖雪峰的官网都是质量很高的教程,不需要在b站上走弯路。最后,我想说说我在这三次作业中的感受。过低的能力或过高的要求都会给我很大的压力,但是在压力下学习效率会比较高,能学到真正有用的知识也会更多。总而言之,在学习过程中越轻松,能学到的东西就越少;越是精神肉体的双重折磨,越是能激发人的潜能。