『BUAA-OO-Unit1-Summary』

『BUAA-OO-Unit1-Summary』

Homework1

一、思路与实现过程

0. 前言:

第一次作业的思考过程是漫长而痛苦的,从周一到周三开启无休止的原地坐牢模式,直到周四早晨的上机,提示代码一下子给了我灵感,接下来利用一个下午的时间完成了作业。但是三周后回过头来重读第一次作业的代码,回想但当时的思考过程,意识到自己完全没有摆脱面向过程的思考模式。

1. 题面:

  • 表达式 → 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项
  • 项 → [加减 空白项] 因子 | 项 空白项 * 空白项 因子
  • 因子 → 变量因子 | 常数因子 | 表达式因子
  • 变量因子 → 幂函数
  • 常数因子 → 带符号的整数
  • 表达式因子 → '(' 表达式 ')' [空白项 指数]
  • 幂函数 → 'x' [空白项 指数]
  • 指数 → '**' 空白项 带符号的整数
  • 带符号的整数 → [加减] 允许前导零的整数
  • 允许前导零的整数 → (0|1|2|…|9){0|1|2|…|9}
  • 空白项 → {空白字符}
  • 空白字符 → space | \t
  • 加减 → + | -

2. 思路:

通过观察,我们可以很自然地发现整个表达式只涉及到了 + , - , * , ** , () 这几个符号 ,并且它们之间存在明确的优先级关系(从左至右优先级逐渐增高,其中 + - 优先级相同)。因此,当时笔者想到了一个自以为妙极了的办法:

* 在解析表达式时(parseExpr),先从左至右遍历字符串,寻找位于圆括号外的 + or -,将表达式(Expr)分割为两部分,再对分割后的部分再次使用parseExpr,直到分割后的部分不存在 + or -,这时不可再分的部分即为定义中的项(Term)。

* 接下来我们来解析项(parseTerm),此时只需寻找圆括号外的*,对项进行反复分割,直至不可再分,这时便得到了因子(Factor)。

因子分为三种类型,举例来说的话就是以下三种形式:

(x + 9) [** 5] , x [** 8] , 25

这时我们发现几种形式中,括号外只存在 ** 这一种运算符了,

* 因此下一步,解析含指数的因子(parsePower),寻找小括号外的**,仍旧进行反复分割,直至不可再分,然后可以发现此时的子结构便只剩下三种形式:

x, num, (...)(不含指数的表达式因子)

好了,下面就好办了。对于形如 (...) 的结构,去掉括号对其再次使用 parseExpr 就可以啦。(递归下降已初具雏形)

递归到何时才到尽头?xnum 即为递归结构中的基本项。如果将整个表达式看做一个树形结构的话,那根节点就是整个式子中出现的那个 优先级最低 的符号,而叶节点即为 xnum

* 在这里笔者将三种情况的处理合并到同一函数parseExprWithPar()(请原谅我的草率命名)

表达式树结构示例如图:

3. 关键实现过程

  • 采用 HashMap<BigInteger, BigInteger> 结构存储最终结果中每一项的系数与指数。
  • 由于表达式数除叶子节点外其余节点均为运算符,因此为统一函数返回类型,建立 Operator 大类,并建立Add, Sub, Mul, Pow四大子类 继承于 Operatorfields 就由节点下方的两个分支Operator组成;对于叶节点,建立一个新的Poly子类,which 依旧 继承于 Operator,但不同于其余的四个运算符节点类Poly类并不需要访问Operatorfields,并且需要创建一个新的 field 来保存基本项的数值。每一次解析后返回 Add/Sub/Mul/Pow/Poly 类并将其 泛化Operator
  • 每种运算的独特性将如何体现呢?利用java 多态(Polymorphism) 的特性,创建 getPoly() 函数实现做出相应计算并返回 HashMap<BigInteger, BigInteger> 的功能。
  • 由于采用表达式树的结构,多余的 +/- 号需要提前处理。保证在 parse 每一个 Expr/Term/Factor 前,字符串中不存在连续多个+/-号的出现,且每种结构最前方的 +/- 需要单独做特殊处理,具体处理方法不再赘述。

二、UML图

* 为避免多余的线条扰乱读者思路,笔者特地将 泛化/继承关系Parser中各方法对类的调用 分成两张图来展示。

  • Generalization

  • ParserMethods/OperatorClasses

三、复杂度分析

  • 方法复杂度
Method CogC ev(G) iv(G) v(G)
Parser.parseTerm(String) 2.0 2.0 2.0 2.0
Parser.parsePower(String) 6.0 4.0 4.0 4.0
Parser.parseExprWithPar(String) 7.0 4.0 4.0 4.0
Parser.parseExpr(String) 9.0 3.0 3.0 3.0
Parser.findSinAstBetweenFactors(String) 6.0 1.0 7.0 8.0
Parser.findPlusOrMinusBetweenTerms(String) 8.0 1.0 9.0 10.0
Parser.findDouAst(String) 6.0 5.0 5.0 6.0
MainClass.print(HashMap) 23.0 1.0 12.0 13.0
MainClass.preHandle(String) 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
expr.Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Sub.getPoly() 4.0 1.0 3.0 3.0
expr.Pow.Pow(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Pow.mulHashMap(HashMap, HashMap) 7.0 1.0 4.0 4.0
expr.Pow.getPoly() 1.0 1.0 2.0 2.0
expr.Poly.Poly(String) 1.0 1.0 1.0 3.0
expr.Poly.getPoly() 0.0 1.0 1.0 1.0
expr.Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Operator.getRight() 0.0 1.0 1.0 1.0
expr.Operator.getPoly() 0.0 1.0 1.0 1.0
expr.Operator.getLeft() 0.0 1.0 1.0 1.0
expr.Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Mul.getPoly() 7.0 1.0 4.0 4.0
expr.Add.getPoly() 4.0 1.0 3.0 3.0
expr.Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Total 92.0 38.0 75.0 81.0
Average 3.68 1.52 3.0 3.24

* 参数解释:

CogC:认知复杂性,随着每个控制结构的使用而增加,而且嵌套控制结构越多,认知复杂性就越高。

ev(G):基本复杂性是一种图论度量方法控制流的结构不良程度的方法。

iv(G):计算方法的设计复杂度。

v(G):计算非抽象方法的圈复杂度。 圈复杂度是对通过每个方法的不同执行路径数量的度量。

MainClass.print(HashMap):主函数的打印函数认知复杂度最高,简化输出结果时多种情况的判断大量使用if/else语句导致了这一结果。

Parser.find...Parser中充当Lexer作用的 find 系列函数复杂度均较高,很有可能是由于实现此系列函数需要遍历整个字符串,并且需要判断的条件语句较多。

  • 类复杂度
Class OCavg OCmax WMC
expr.Add 2.0 3.0 4.0
expr.Mul 2.5 4.0 5.0
expr.Operator 1.0 1.0 4.0
expr.Poly 2.5 4.0 5.0
expr.Pow 2.3333333333333335 4.0 7.0
expr.Sub 2.0 3.0 4.0
MainClass 5.0 12.0 15.0
Parser 4.142857142857143 6.0 29.0
Total 73.0
Average 2.92 4.625 9.125

* 参数解释:

OCavg:计算每个类中非抽象方法的平均圈复杂度。

OCmax:计算每个类中非抽象方法的最大圈复杂度。

WMC: 计算每个类中方法的总圈复杂度。

四、Debug

第一次作业强测通过。

互测卡了两个 bug

  • 在对形如 -(...) ** 6 / - x ** 6 的表达式进行解析时,将-x/(...) 看做一个整体, 最终得出(...) ** 6 / x ** 6 的错误结果。
    • 解决方案:解析指数 ** 符号时,也要先预判因子前是否有前导 +/-
  • 这个就很奇葩了。print 优化时出现失误,遇到 x 便会输出 -x
    • 解决方案:改变一下分支条件,一处笔误。(就这,还能过强测?)

Homework2

一、迭代思路与实现过程

0. 前言:

第二次作业新增了三角函数sum求和函数以及自定义函数的求解。值得纪念的是,笔者本学期的第一次刷夜献给了你。

1. 题面:

  • 表达式 → 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项
  • 项 → [加减 空白项] 因子 | 项 空白项 '*' 空白项 因子
  • 因子 → 变量因子 | 常数因子 | 表达式因子
  • 变量因子 → 幂函数 | 三角函数 | 自定义函数调用 | 求和函数
  • 常数因子 → 带符号的整数
  • 表达式因子 → '(' 表达式 ')' [空白项 指数]
  • 幂函数 → (函数自变量|'i') [空白项 指数]
  • 三角函数 → 'sin' 空白项 '(' 空白项 因子 空白项 ')' [空白项 指数] | 'cos' 空白项 '(' 空白项 因子 空白项 ')' [空白项 指数]
  • 指数 → '**' 空白项 ['+'] 允许前导零的整数 (与上次作业不同)
  • 带符号的整数 → [加减] 允许前导零的整数
  • 允许前导零的整数 → (0|1|2|…|9){0|1|2|…|9}
  • 空白项 → {空白字符}
  • 空白字符 → space | \t
  • 加减 → '+' | '-'
  • 自定义函数定义 → 自定义函数名 空白项 '(' 空白项 函数自变量 空白项 [',' 空白项 函数自变量 空白项 [',' 空白项 函数自变量 空白项]] ')' 空白项 '=' 空白项 函数表达式
  • 函数自变量 → 'x' | 'y' | 'z'
  • 自定义函数调用 → 自定义函数名 空白项 '(' 空白项 因子 空白项 [',' 空白项 因子 空白项 [',' 空白项 因子 空白项]] ')'
  • 自定义函数名 → 'f' | 'g' | 'h'
  • 求和函数 → 'sum' '(' 空白项 'i' 空白项',' 空白项 常数因子 空白项 ',' 空白项 常数因子 空白项 ',' 空白项 求和表达式 空白项 ')'
  • 函数表达式 → 表达式
  • 求和表达式 → 因子

2. 思路:

相较于HW1的重要变化:

  • 输出表达式形式变得更加复杂(丑陋),形如\(\ \sum a*x^{b}*\prod_{i} cos(E_i)^{c_i}*\prod_{j} cos(E_j)^{c_j}\) 的表达式需要更复杂的数据结构来进行存储。经讨论课大家的商讨,我决定采用 HashMap1<HashMap2<String, index>, coeff> 的形式加以存储,并且为简化结构提高代码可读性,优化过程中我又将HashMap2<String, index>单独提取出来,新建了一个类ResultTerm
  • 严格意义上来讲,sin/cos也是运算符的一种,而与 +/-/*/** 不同的是,三角函数的运算操作数只有一个,属于单目运算符。因此,一种更为合理的思路应当是将 sin/cos 也看作与 Operator 具有继承关系,单独建立子类。
  • 而笔者在这里却并没有选择这样处理。而是将 DIYFunc/sum/sin,cos 三种情况同时加入 parseExprWithPar 中解析,并且将sin/cosx,num等量齐观,同视为最小项。最终在Poly函数中共同解析,然而这样的方法也为第三次作业埋下了一枚地雷,我们一会儿再说。
  • 在处理DIYFunction/sum时,笔者采用了直接进行字符串替换的方式。但这里就出现了一个小问题,如果直接进行字符串替换会不会对表达式整体结构产生破坏?比方说f(x) = x ** 2; f(-1),如果直接进行替换结果必然会出错;而如果加上括号再进行替换的话,形如f(x) = sin(x); f(x ** 2) 的输出就会破坏第二次作业要求的表达式形式。因此,一会儿快进到第三次作业的迭代。

二、UML图

与第一次的内容区别不大,添加了 ResultTerm 类来存储表达式多因子项与指数。

能够体现在uml图上的变动仅此一处,因此不再赘余插图。

三、复杂度分析

  • 方法复杂度
Method CogC ev(G) iv(G) v(G)
Parser.sum(String) 1.0 1.0 2.0 2.0
Parser.parseTerm(String) 2.0 2.0 2.0 2.0
Parser.parsePower(String) 6.0 4.0 4.0 4.0
Parser.parseExprWithPar(String) 10.0 6.0 9.0 9.0
Parser.parseExpr(String) 9.0 3.0 3.0 3.0
Parser.func(String) 8.0 6.0 6.0 6.0
Parser.findSinAstBetweenFactors(String) 7.0 1.0 7.0 9.0
Parser.findPlusOrMinusBetweenTerms(String) 9.0 1.0 9.0 11.0
Parser.findDouAst(String) 6.0 5.0 5.0 6.0
MainClass.print(HashMap) 15.0 1.0 7.0 8.0
MainClass.preHandle(String) 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
MainClass.getFuncs() 0.0 1.0 1.0 1.0
expr.Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Sub.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
expr.Sub.getPoly() 8.0 4.0 5.0 5.0
expr.ResultTerm.ResultTerm() 0.0 1.0 1.0 1.0
expr.ResultTerm.replace(String, Integer) 0.0 1.0 1.0 1.0
expr.ResultTerm.mul(ResultTerm, ResultTerm) 5.0 1.0 4.0 4.0
expr.ResultTerm.getResultTerm() 0.0 1.0 1.0 1.0
expr.ResultTerm.add(String, Integer) 0.0 1.0 1.0 1.0
expr.Pow.Pow(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Pow.mulExpr(HashMap, HashMap) 13.0 5.0 6.0 6.0
expr.Pow.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
expr.Pow.getPoly() 3.0 2.0 3.0 3.0
expr.Poly.Poly(String) 4.0 1.0 4.0 4.0
expr.Poly.getPoly() 0.0 1.0 1.0 1.0
expr.Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Operator.getRight() 0.0 1.0 1.0 1.0
expr.Operator.getResult() 0.0 1.0 1.0 1.0
expr.Operator.getPoly() 0.0 1.0 1.0 1.0
expr.Operator.getLeft() 0.0 1.0 1.0 1.0
expr.Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
expr.Mul.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
expr.Mul.getPoly() 13.0 5.0 6.0 6.0
expr.Add.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
expr.Add.getPoly() 8.0 4.0 5.0 5.0
expr.Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Total 152.0 89.0 121.0 135.0
Average 4.0 2.3421052631578947 3.1842105263157894 3.5526315789473686

expr.Mul.getPoly()以及expr.Pow.mulExpr(HashMap, HashMap)

以上两个函数均涉及到了HashMap的乘法计算,遍历次数较多,因此认知复杂度偏高。

其余情况均与第一次作业类似。

  • 类复杂度
Class OCavg OCmax WMC
eexpr.Add 3.6666666666666665 5.0 11.0
expr.Mul 4.0 6.0 12.0
expr.Operator 1.0 1.0 5.0
expr.Poly 2.5 4.0 5.0
expr.Pow 3.75 6.0 15.0
expr.ResultTerm 1.6 4.0 8.0
expr.Sub 3.6666666666666665 5.0 11.0
MainClass 2.75 7.0 11.0
Parser 4.555555555555555 7.0 41.0
Total 119.0
Average 3.1315789473684212 5.0 13.222222222222221

Parser类WMC呈爆炸式增长。

主要是由于笔者的设计不合理,导致处理新增结构的函数全都被堆在了一个 Parser 类中。

四、Debug

互测完美通过。

强测完美翻车。

TLE了五个点,你在强测中得到了 59.212 分 的悲痛瞬间如潮水般涌尽了 受到 hack: 0/12 的喜悦。

这主要是由以下两个bug引起的:

  • 处理 sum 函数时,采用了 StringBuilder 字符串拼接的方式。这就导致形如sum(i, -3, -1, i)函数经处理后转换为表达式-3+-2+-1,出现多个正负号并且未经过预处理因而无法正常解析。
    • 解决方案:最简单也最直接的方式莫过于在 替换后解析前 对字符串调用一次预处理函数。然而这并不是我们想要的答案,对字符串进行替换 远不如 直接对整体结构直接替换 来的稳妥。因此,预期使用 StringBuider 函数构造一长串求和表达式,倒不如在对 i 遍历时,直接创建 Add() 类直接构造分解后的表达式树形式。
  • 不严格考虑形式化表述要求,对于形如 x ** 5 ** 2 的因子应如何处理?换句话说,假设在对f(x) = x ** 2; f(x**5) 这个表达式进行替换时,在代入变量时没有在 x**5 两侧加上一层括号,而是直接代入,获得形如 x**5**2 的表达式,是否会解析成功?
    • 答案:使用笔者的架构是可以解析成功的。因为笔者的 Lexer代码在对 Factor 进行解构时,率先返回值是圆括号外出现的最后一个 ** 的位置序号。换个角度来理解,这里的乘方运算应当是自左向右进行的,即 (x**5)**2为解析该表达式的正确方法。写到这里,笔者情不自禁地想到了PowerTower/Tetration,这种幂次计算法则规定乘方运算应自由向左进行。如果我们的程序想要处理这种运算,在出现多个 ** 符号时,就要率先返回首次出现该运算符的位置了。(这不重要,纯属笔者的胡思乱想。总而言之,字符串的直接替换是十分不可靠的,能够直接对结构进行替换就一定在节点向下添枝叶,如果实在没有办法也一定要加上括号再替换)

Homework3

一、迭代思路与过程

0. 前言:

第三次作业新增了 括号嵌套 以及 自定义/三角函数的嵌套

1. 题面:

与Homework2完全相同

2. 思路:

由于前两次作业均采用了递归下降算法,因此嵌套的问题已基本完全解决,没有崭新的思路值得一提。

3. 关键实现过程

  • 由于HW2中规定sin/cos的操作数一定是 幂函数或数字 ,因此将其当做基本项在Poly函数中处理是具有一定合理性的。然而HW3中允许三角函数的嵌套,再将其当做基本项显然是不合适的。然而笔者却这么做了 (当时的我完全失去了理智,忘记了面向对象的初心),对基本项sin/cos()圆括号中的再次应用了parseExpr函数。这样的做法显然是可以的,但从架构设计的角度来讲实在是没有道理。这一点将在 反思改进模块 详细展开。

二、UML图

同HW2,且笔者对自己的架构设计不是很满意,随后会在 反思改进模块 给出新架构的UML类图。

三、复杂度分析

  • 方法复杂度
Method CogC ev(G) iv(G) v(G)
Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
Sub.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Sub.getPoly() 8.0 4.0 5.0 5.0
ResultTerm.ResultTerm() 0.0 1.0 1.0 1.0
ResultTerm.replace(String, Integer) 0.0 1.0 1.0 1.0
ResultTerm.mul(ResultTerm, ResultTerm) 5.0 1.0 4.0 4.0
ResultTerm.getResultTerm() 0.0 1.0 1.0 1.0
ResultTerm.add(String, Integer) 0.0 1.0 1.0 1.0
Pow.Pow(Operator, Operator) 0.0 1.0 1.0 1.0
Pow.mulExpr(HashMap, HashMap) 13.0 5.0 6.0 6.0
Pow.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Pow.getPoly() 3.0 2.0 3.0 3.0
Poly.Poly(String) 4.0 1.0 4.0 4.0
Poly.getPoly() 0.0 1.0 1.0 1.0
Parser.sum(String) 1.0 1.0 2.0 2.0
Parser.parseTerm(String) 2.0 2.0 2.0 2.0
Parser.parsePower(String) 6.0 4.0 4.0 4.0
Parser.parseExprWithPar(String) 10.0 6.0 9.0 9.0
Parser.parseExpr(String) 9.0 3.0 3.0 3.0
Parser.func(String) 8.0 6.0 6.0 6.0
Parser.findSinAstBetweenFactors(String) 7.0 1.0 7.0 9.0
Parser.findPlusOrMinusBetweenTerms(String) 9.0 1.0 9.0 11.0
Parser.findNextCommaInOneParenthesis(String, int) 8.0 3.0 4.0 7.0
Parser.findDouAst(String) 6.0 1.0 5.0 6.0
Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
Operator.getRight() 0.0 1.0 1.0 1.0
Operator.getResult() 0.0 1.0 1.0 1.0
Operator.getPoly() 0.0 1.0 1.0 1.0
Operator.getLeft() 0.0 1.0 1.0 1.0
Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
Mul.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Mul.getPoly() 13.0 5.0 6.0 6.0
MainClass.preHandle(String) 0.0 1.0 1.0 1.0
MainClass.opToString(HashMap) 14.0 1.0 7.0 8.0
MainClass.numOfTerms(HashMap) 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
MainClass.getFuncs() 0.0 1.0 1.0 1.0
Add.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Add.getPoly() 8.0 4.0 5.0 5.0
Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Total 159.0 89.0 126.0 143.0
Average 3.975 2.225 3.15 3.575
  • 类复杂度
Class OCavg OCmax WMC
Add 3.6666666666666665 5.0 11.0
MainClass 2.4 7.0 12.0
Mul 4.0 6.0 12.0
Operator 1.0 1.0 5.0
Parser 4.7 7.0 47.0
Poly 2.5 4.0 5.0
Pow 3.75 6.0 15.0
ResultTerm 1.6 4.0 8.0
Sub 3.6666666666666665 5.0 11.0
Total 126.0
Average 3.15 5.0 14.0

脑血栓后遗症留下的老毛病了,不再赘述。

四、Debug

强测翻车一个点,性能分... 我们先不管它(

  • 关于多变量函数的问题:f(f(x,x**1),x**+1) 。正则捕获几乎是大家公认的解析自定义/求和函数的最佳办法,而我却采用了找 , 的方法。在没有括号嵌套的情况下,直接采用上述方法似乎合理。然而加入括号嵌套了以后,情况就变得有些复杂了,因为即使成功获得了 自定义函数调用 的单元,内部的每一个 , 也不一定都是分离调用因子的 , ,例子如上。
    • 解决方案:单独写一个 findNextCommaInOneParethesis() 来返回从字符串指定位置开始出现的第一个只被套在一层括号内的 ,(完全没有必要,正则分组匹配,正则分组匹配,正则分组匹配!!!)

互测被Hack 5 个测试点,但均为同质Bug

  • sum 无法处理超出 int 范围的大数。
    • 解决方案:int --> BigInteger

反思改进

一、思路

  • 表达式树 的结构来观测全局。

  • 我们发现,仍然可以用 Operator 作为父类,统领所有的运算符号。* 将 SinCos 三角函数单独建为一类,看做一个单目运算符;* 将DIYFunc单独建为一类,遇到匹配结构即在提取与替换后以表达式树的形式扦插在函数节点的下方;* 最后再将Sum单独建为一类,工作方式与DIYFunc同理。
  • 这样,仍采用与先前一样的模式进行递归下降分析,递归的基本项依然是 xnum,将返回值泛化为 Operator 类,调用 getPoly() 方法,获得由相应节点运算符计算出的结果值。

二、UML图

  • 图中即为各子类与 Operator 父类的继承关系。 (其中,由上至下符号运算优先级逐渐降低)

三、复杂度分析

  • 方法复杂度
Method CogC ev(G) iv(G) v(G)
Sum.Sum(String) 1.0 1.0 2.0 2.0
Sum.getPoly() 0.0 1.0 1.0 1.0
Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
Sub.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Sub.getPoly() 8.0 4.0 5.0 5.0
SinCos.SinCos(String) 2.0 1.0 3.0 3.0
SinCos.getPoly() 0.0 1.0 1.0 1.0
ResultTerm.ResultTerm() 0.0 1.0 1.0 1.0
ResultTerm.replace(String, Integer) 0.0 1.0 1.0 1.0
ResultTerm.mul(ResultTerm, ResultTerm) 5.0 1.0 4.0 4.0
ResultTerm.getResultTerm() 0.0 1.0 1.0 1.0
ResultTerm.add(String, Integer) 0.0 1.0 1.0 1.0
Pow.Pow(Operator, Operator) 0.0 1.0 1.0 1.0
Pow.mulExpr(HashMap, HashMap) 13.0 5.0 6.0 6.0
Pow.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Pow.getPoly() 3.0 2.0 3.0 3.0
Poly.Poly(String) 2.0 1.0 2.0 2.0
Poly.getPoly() 0.0 1.0 1.0 1.0
Parser.parseTerm(String) 2.0 2.0 2.0 2.0
Parser.parsePower(String) 6.0 4.0 4.0 4.0
Parser.parseExprWithPar(String) 12.0 7.0 10.0 11.0
Parser.parseExpr(String) 9.0 3.0 3.0 3.0
Parser.findSinAstBetweenFactors(String) 7.0 1.0 7.0 9.0
Parser.findPlusOrMinusBetweenTerms(String) 9.0 1.0 9.0 11.0
Parser.findDouAst(String) 6.0 1.0 5.0 6.0
Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
Operator.getRight() 0.0 1.0 1.0 1.0
Operator.getResult() 0.0 1.0 1.0 1.0
Operator.getPoly() 0.0 1.0 1.0 1.0
Operator.getLeft() 0.0 1.0 1.0 1.0
Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
Mul.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Mul.getPoly() 13.0 5.0 6.0 6.0
MainClass.preHandle(String) 0.0 1.0 1.0 1.0
MainClass.opToString(HashMap) 14.0 1.0 7.0 8.0
MainClass.numOfTerms(HashMap) 0.0 1.0 1.0 1.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
MainClass.getFuncs() 0.0 1.0 1.0 1.0
DIYFunc.getPoly() 0.0 1.0 1.0 1.0
DIYFunc.findNextCommaInOneParenthesis(String, int) 8.0 3.0 4.0 7.0
DIYFunc.DIYFunc(String) 8.0 1.0 6.0 6.0
Add.isEqualResultTerm(ResultTerm, ResultTerm) 6.0 5.0 4.0 6.0
Add.getPoly() 8.0 4.0 5.0 5.0
Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Total 161.0 89.0 131.0 149.0
Average 3.659090909090909 2.022727272727273 2.977272727272727 3.3863636363636362
  • 类复杂度
Class OCavg OCmax WMC
Add 3.6666666666666665 5.0 11.0
DIYFunc 4.333333333333333 6.0 13.0
MainClass 2.4 7.0 12.0
Mul 4.0 6.0 12.0
Operator 1.0 1.0 5.0
Parser 4.857142857142857 7.0 34.0
Poly 1.5 2.0 3.0
Pow 3.75 6.0 15.0
ResultTerm 1.6 4.0 8.0
SinCos 2.0 3.0 4.0
Sub 3.6666666666666665 5.0 11.0
Sum 1.5 2.0 3.0
Total 131.0
Average 2.977272727272727 4.5 10.916666666666666
  • 可以看到,各类指标数值直线下降。

Ultimate Summary

  • 总的来说,这次作业可以说是用面向过程的思考方式写出的面向对象的代码。()
  • 有没有发现这个人总是对“自动化测试”这个话题避而不谈?
    • 没错,这个人没有使用自动化测试。
    • 这一定要开始学习编写测试程序了,不然强测互测真的会死的很惨的(2333)

一段优雅的代码

if(input.charAt(pos) == ' ' || input.charAt(pos) == '\t')
-->
if(" \t".indexOf(input.charAt(pos)) != -1)
posted @ 2022-03-26 13:33  augusto_13  阅读(14)  评论(1编辑  收藏  举报