OO第一单元作业
OO第一单元作业
BearHuchao 2020年3月19日
肝OO代码就像喝酒,要顺畅,痛快才行。顺畅起来后,本来只能肝一两的,发现肝半斤都不在话下。如果不顺畅,半两就晕了,立即睡觉理理气,明天继续肝😂
——吴际
前言
这个学期是第一次正式接触Java编程语言。虽然在上学期选修了Java程序设计这门一般专业课,但是所有的代码都是在几天之内匆匆赶制而成,而且使用的是JavaFX,比较注重图形化界面的开发。这学期开始的OO课程第一次正式系统的在老师的带领下使用Java编程语言。
第一次作业
第一次作业是三次作业中最简单的一次。主要思想是使用小正则来对输入的表达式进行格式化处理,然后使用统一的正则表达式来对系数和指数来进行匹配。第一次作业的主类还是负责了相当的输入输出,不太好看,具体数据如下:
UML类图:
复杂度分析:
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
MainClass.main(String[]) | 1 | 7 | 7 |
MainClass.parseInput(String) | 1 | 3 | 3 |
MainClass.preTreatString(String) | 2 | 1 | 3 |
Term.Term(BigInteger,BigInteger) | 1 | 1 | 1 |
Term.Term(String,String,String) | 1 | 2 | 2 |
Term.add(Term) | 1 | 1 | 1 |
Term.diff() | 1 | 1 | 1 |
Term.equals(Object) | 2 | 3 | 3 |
Term.getCoeff() | 1 | 1 | 1 |
Term.getDegree() | 1 | 1 | 1 |
Term.hashCode() | 1 | 1 | 1 |
Term.isGtz() | 1 | 1 | 1 |
Term.setCoeff(BigInteger) | 1 | 1 | 1 |
Term.setDegree(BigInteger) | 1 | 1 | 1 |
Term.toString() | 2 | 3 | 7 |
Class | OCavg | WMC |
---|---|---|
MainClass | 4 | 12 |
Term | 1.67 | 20 |
第二次作业
第二次作业也使用了格式化输入的思想,由于题目中出现的多项式可能是幂函数x(**index)
,常数coeff
,三角函数(sin|cos)(x)(**index)
,所以我们只需要逐项对相关的项及其系数、指数进行匹配,顺带进行WF的判断(判断的原理是看前后哦两次匹配到的结果是否相连)。在这样的基础上,我构建了基于幂函数和三角函数指数的因子类Factor
,并使用了HashMap<BigInteger, Factor>
容器来储存表达式。最后使用 Wolfram Mathematics 工具得到固定的导函数,求导过程如下:
D[coeff*x^varIndex*Sin[x]^sinIndex*Cos[x]^cosIndex, x]
,即对
求导,得到如下结果:
coeff sinIndex x^varIndex Cos[x]^(1 + cosIndex) Sin[x]^(-1 + sinIndex)
+ coeff varIndex x^(-1 + varIndex) Cos[x]^cosIndex Sin[x]^sinIndex
- coeff cosIndex x^varIndex Cos[x]^(-1 + cosIndex) Sin[x]^(1 + sinIndex)
,也即
重写toString
方法可以实现性能的优化,由于本人能力有限,仅实现了对指数和系数的优化。
另外,本次作业出现了对
UML类图:
代码复杂度分析:
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
Expr.Expr() | 1 | 1 | 1 |
Expr.Expr(String) | 8 | 10 | 12 |
Expr.add(ArrayList |
1 | 2 | 2 |
Expr.add(TermEntry) | 1 | 2 | 2 |
Expr.diff() | 1 | 2 | 2 |
Expr.initTerm(Matcher) | 1 | 1 | 1 |
Expr.modifyTerm(TermEntry,Matcher) | 7 | 7 | 11 |
Expr.sign(String,String) | 1 | 3 | 4 |
Expr.toString() | 1 | 3 | 3 |
Factor.Factor() | 1 | 1 | 1 |
Factor.Factor(BigInteger,BigInteger,BigInteger) | 1 | 1 | 1 |
Factor.equals(Object) | 3 | 4 | 6 |
Factor.getCosIndex() | 1 | 1 | 1 |
Factor.getSinIndex() | 1 | 1 | 1 |
Factor.getVarIndex() | 1 | 1 | 1 |
Factor.hashCode() | 1 | 1 | 1 |
Factor.setCosIndex(BigInteger) | 1 | 1 | 1 |
Factor.setSinIndex(BigInteger) | 1 | 1 | 1 |
Factor.setVarIndex(BigInteger) | 1 | 1 | 1 |
Factor.toString() | 1 | 8 | 10 |
MainClass.main(String[]) | 1 | 6 | 6 |
TermEntry.TermEntry(Factor,BigInteger) | 1 | 1 | 1 |
TermEntry.TermEntry(int) | 1 | 1 | 1 |
TermEntry.addCosIndex(BigInteger) | 1 | 1 | 1 |
TermEntry.addSinIndex(BigInteger) | 1 | 1 | 1 |
TermEntry.addVarIndex(BigInteger) | 1 | 1 | 1 |
TermEntry.diff() | 1 | 1 | 1 |
TermEntry.equals(Object) | 3 | 3 | 5 |
TermEntry.getKey() | 1 | 1 | 1 |
TermEntry.getValue() | 1 | 1 | 1 |
TermEntry.hashCode() | 1 | 1 | 1 |
TermEntry.isPositive() | 1 | 1 | 1 |
TermEntry.setValue(BigInteger) | 1 | 1 | 1 |
TermEntry.timesCoeff(BigInteger) | 1 | 1 | 1 |
TermEntry.toString() | 5 | 3 | 6 |
WrongFormatException.WrongFormatException() | 1 | 1 | 1 |
Class | OCavg | WMC |
---|---|---|
Expr | 3.78 | 34 |
Factor | 2 | 22 |
MainClass | 4 | 4 |
TermEntry | 1.5 | 21 |
WrongFormatException | 1 | 1 |
第三次作业
第三次作业是最难的一次,我也是压线提交,差点就死掉了(不过最后还是死于括号的问题)。本人的思路是在构造过程中使用逆波兰表达式和调车场算法来实现将字符串转化为表达式树。在实际转换的过程中,分别使用三个方法来实现题目中对应的表达式、项和因子,其中表达式因子当作表达式来处理。既然构建了表达式树,那么我们就可以通过递归的方式来求导。由于个人能力有限,对求导完的树没有进行任何优化,原样输出。
UML类图:
代码复杂度分析:
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
Input.getInput() | 3 | 4 | 5 |
MainClass.main(String[]) | 2 | 2 | 3 |
Tree.Tree(String) | 1 | 3 | 3 |
Tree.diffString() | 1 | 1 | 1 |
Tree.findNextSig() | 1 | 2 | 3 |
Tree.getIndex(Matcher) | 2 | 1 | 2 |
Tree.getType(String) | 8 | 2 | 8 |
Tree.isLower(String,String) | 2 | 1 | 3 |
Tree.preProc() | 3 | 1 | 4 |
Tree.procExpr() | 6 | 5 | 10 |
Tree.procFactor(boolean) | 7 | 12 | 18 |
Tree.procIndex() | 1 | 4 | 4 |
Tree.procTerm(boolean) | 7 | 5 | 10 |
Tree.pushOpStack(String) | 8 | 6 | 11 |
Tree.pushTreeStack(TreeNode) | 3 | 2 | 5 |
TreeNode.TreeNode(BigInteger) | 1 | 1 | 1 |
TreeNode.TreeNode(TreeNodeType,BigInteger,TreeNode,TreeNode) | 1 | 1 | 1 |
TreeNode.diff() | 5 | 4 | 9 |
TreeNode.getLeft() | 1 | 1 | 1 |
TreeNode.getRight() | 1 | 1 | 1 |
TreeNode.getType() | 1 | 1 | 1 |
TreeNode.minusToString() | 4 | 4 | 5 |
TreeNode.plusToString() | 4 | 3 | 5 |
TreeNode.powerToString() | 4 | 3 | 4 |
TreeNode.setLeft(TreeNode) | 1 | 1 | 1 |
TreeNode.setRight(TreeNode) | 1 | 1 | 1 |
TreeNode.timesToString() | 5 | 8 | 11 |
TreeNode.toString() | 3 | 2 | 11 |
WrongFormatException.WrongFormatException() | 1 | 1 | 1 |
Class | OCavg | WMC |
---|---|---|
Input | 4 | 4 |
MainClass | 2 | 2 |
Tree | 5.46 | 71 |
TreeNode | 3.54 | 46 |
TreeNodeType | n/a | 0 |
WrongFormatException | 1 | 1 |
本次作业将输入彻底分离。
Bug分析
第一次作业很简单,没什么bug;
第二次作业最主要的bug可能出现在优化的过程中,本人并未涉及;
第三次作业的bug主要出现在WF的判定以及表达式树的构建中,另外,在输出的时候,由于后缀表达式没有括号,需要注意在toString
方法中对括号的处理(例如减法、三角函数中的表达式因子)。
发现别人的Bug
整个互测的过程中,我并没有使用自动化测试工具来发现他人代码的Bug,更多的是自己手动构造样例(比如对指数的特判等)。需要注意的是,在强测前,对自己的代码进行相应的测试是非常有必要的。
心得和体会
- 正则表达式的使用是重点,但应该尽量避免写出大正则。
- 最后一次作业想到了可能出现的bug,但是没有进行相应的覆盖测试,导致强测只有60分。