OO第一单元总结(BUAA)
本博客作为我对2022年BUAA-OO课程第一次作业的总结。主要包含我的作业设计思路和在编程过程中个人的一些感悟和理解。
一、问题描述
通过对表达式结构进行建模,完成多层嵌套表达式和函数调用的括号展开与化简。
表达式的形式化描述如下:
表达式 → 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项
项 → [加减 空白项] 因子 | 项 空白项 '*' 空白项 因子
因子 → 变量因子 | 常数因子 | 表达式因子
变量因子 → 幂函数 | 三角函数 | 自定义函数调用 | 求和函数
常数因子 → 带符号的整数
表达式因子 → '(' 表达式 ')' [空白项 指数]
幂函数 → (函数自变量|'i') [空白项 指数]
三角函数 → 'sin' 空白项 '(' 空白项 因子 空白项 ')' [空白项 指数] | 'cos' 空白项 '(' 空白项 因子 空白项 ')' [空白项 指数]
指数 → '**' 空白项 ['+'] 允许前导零的整数
带符号的整数 → [加减] 允许前导零的整数
允许前导零的整数 → (0|1|2|…|9){0|1|2|…|9}
空白项 → {空白字符}
空白字符 →
`(空格) |\t`加减 → '+' | '-'
自定义函数定义 → 自定义函数名 空白项 '(' 空白项 函数自变量 空白项 [',' 空白项 函数自变量 空白项 [',' 空白项 函数自变量 空白项]] ')' 空白项 '=' 空白项 函数表达式
函数自变量 → 'x' | 'y' | 'z'
自定义函数调用 → 自定义函数名 空白项 '(' 空白项 因子 空白项 [',' 空白项 因子 空白项 [',' 空白项 因子 空白项]] ')'
自定义函数名 → 'f' | 'g' | 'h'
求和函数 → 'sum' '(' 空白项 'i' 空白项',' 空白项 常数因子 空白项 ',' 空白项 常数因子 空白项 ',' 空白项 求和表达式 空白项 ')'
函数表达式 → 表达式
求和表达式 → 因子
二、基本思路
解析表达式 → 实例化表达式 → 化简表达式 → 输出表达式
基本思路如下图:解析表达式的工作交给 lexer 类进行完成,实例化表达式则是由表达式类、项类以及各个因子类的构造方法递归调用共同完成,化简表达式则是由这些类的 simplify 方法递归调用完成,而输出表达式则是由这些类的 toString 方法完成。

三、程序结构与BUG分析
第一次作业
程序结构分析:
需求简介:
通过对包含加减乘除和乘方的表达式结构进行建模,完成单变量多项式的括号展开,输出不带有括号的恒等表达式。
代码架构:
代码的UML图如下:

程序规模和复杂度分析:
类复杂度分析:
| OCarg | OCmax | WMC | |
|---|---|---|---|
| Main | 1.0 | 1.0 | 1.0 |
| NumberFactor | 1.7 | 4.0 | 17.0 |
| ComplexFactor | 1.8 | 3.0 | 9.0 |
| SimpleFactor | 1.833 | 4.0 | 11.0 |
| Expression | 2.571 | 5.0 | 18.0 |
| Lexer | 3.375 | 9.0 | 27.0 |
| Term | 5.2 | 10.0 | 52.0 |
| Total | 135.0 | ||
| Average | 2.872 | 5.143 | 19.286 |
方法复杂度分析:
| CogC | ev(G) | iv(G) | v(G) | |
|---|---|---|---|---|
| Term.turnString() | 11.0 | 6.0 | 8.0 | 9.0 |
| Term.tryCombine(Term) | 27.0 | 7.0 | 12.0 | 15.0 |
| Term.Term(Lexer) | 12.0 | 1.0 | 10.0 | 10.0 |
| Term.simplify(ArrayList) | 6.0 | 1.0 | 5.0 | 5.0 |
| Term.multTerm(Term) | 2.0 | 1.0 | 3.0 | 3.0 |
| Term.hasNumber() | 3.0 | 3.0 | 1.0 | 3.0 |
| Term.hasComplexFactor() | 3.0 | 3.0 | 1.0 | 3.0 |
| Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.combine() | 15.0 | 1.0 | 8.0 | 8.0 |
| Term.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.turnString() | 4.0 | 4.0 | 4.0 | 4.0 |
| SimpleFactor.simplify() | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.SimpleFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| SimpleFactor.setPow(int) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.sameAs(SimpleFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| NumberFactor.simplify() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setSysmbol(boolean) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setNumber(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.sameAs(NumberFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.NumberFactor(Lexer) | 3.0 | 1.0 | 3.0 | 3.0 |
| NumberFactor.multNumber(BigInteger, boolean) | 1.0 | 1.0 | 1.0 | 2.0 |
| NumberFactor.isSysmbol() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.getNumber() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.addNumber(BigInteger, boolean) | 6.0 | 1.0 | 4.0 | 4.0 |
| Main.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.next() | 11.0 | 3.0 | 7.0 | 9.0 |
| Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getPos() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getNumber() | 2.0 | 1.0 | 3.0 | 3.0 |
| Lexer.getExpression() | 6.0 | 3.0 | 3.0 | 5.0 |
| Lexer.deleteSpace() | 4.0 | 3.0 | 3.0 | 3.0 |
| Lexer.addOrSub() | 7.0 | 5.0 | 3.0 | 5.0 |
| Expression.turnString() | 4.0 | 3.0 | 4.0 | 4.0 |
| Expression.simplify() | 1.0 | 1.0 | 2.0 | 2.0 |
| Expression.multExpression(Expression) | 3.0 | 1.0 | 3.0 | 3.0 |
| Expression.getTerms() | 0.0 | 1.0 | 1.0 | 1.0 |
| Expression.Expression(Lexer) | 1.0 | 1.0 | 2.0 | 2.0 |
| Expression.combine() | 8.0 | 4.0 | 4.0 | 5.0 |
| Expression.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| ComplexFactor.simplify() | 1.0 | 1.0 | 2.0 | 2.0 |
| ComplexFactor.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.getExpression() | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.ComplexFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| Total | 153.0 | 82.0 | 126.0 | 142.0 |
| Average | 3.255 | 1.741 | 2.681 | 3.021 |
BUG分析:
第一次作业较为简单,架构清晰,没有出现BUG。
第二次作业
程序结构:
需求简介:
通过对包含加减乘除乘方以及简单三角函数、自定义函数和求和函数的表达式结构进行建模,完成多项式的括号展开与函数调用、化简,输出不带有括号的恒等表达式。
代码架构:
代码的UML图如下:

程序规模和复杂度分析:
类复杂度分析:
| OCavg | OCmax | WMC | |
|---|---|---|---|
| AllMyFunction | 3.0 | 5.0 | 9.0 |
| ComplexFactor | 2.2 | 3.0 | 11.0 |
| Expression | 2.75 | 5.0 | 22.0 |
| Function | 2.667 | 6.0 | 8.0 |
| FunctionFactor | 1.0 | 1.0 | 3.0 |
| Lexer | 3.667 | 10.0 | 33.0 |
| Main | 2.0 | 2.0 | 2.0 |
| NumberFactor | 2.308 | 6.0 | 30.0 |
| SimpleFactor | 2.375 | 4.0 | 19.0 |
| SumFunctionFactor | 6.667 | 14.0 | 20.0 |
| Term | 4.75 | 13.0 | 76.0 |
| TrigonometricFunction | 3.1 | 11.0 | 31.0 |
| Total | 264.0 | ||
| Average | 3.219 | 6.667 | 22.0 |
方法复杂度分析:
| CogC | ev(G) | iv(G) | v(G) | |
|---|---|---|---|---|
| TrigonometricFunction.turnStringSpecial() | 3.0 | 2.0 | 2.0 | 3.0 |
| TrigonometricFunction.turnString() | 5.0 | 3.0 | 2.0 | 4.0 |
| TrigonometricFunction.tryCombine(TrigonometricFunction) | 2.0 | 2.0 | 1.0 | 2.0 |
| TrigonometricFunction.TrigonometricFunction(Lexer) | 19.0 | 1.0 | 10.0 | 12.0 |
| TrigonometricFunction.toString() | 5.0 | 3.0 | 2.0 | 4.0 |
| TrigonometricFunction.simplify(AllMyFunction) | 2.0 | 2.0 | 1.0 | 2.0 |
| TrigonometricFunction.setPow(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.compareTo(TrigonometricFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.combine(TrigonometricFunction) | 2.0 | 1.0 | 2.0 | 2.0 |
| Term.turnStringSpecial() | 4.0 | 4.0 | 2.0 | 4.0 |
| Term.turnString() | 13.0 | 6.0 | 9.0 | 11.0 |
| Term.tryCombine(Term) | 2.0 | 2.0 | 1.0 | 2.0 |
| Term.toString() | 13.0 | 6.0 | 9.0 | 11.0 |
| Term.termCombine(Term) | 14.0 | 4.0 | 7.0 | 8.0 |
| Term.Term(Lexer) | 3.0 | 1.0 | 4.0 | 4.0 |
| Term.sortFactors() | 5.0 | 1.0 | 4.0 | 4.0 |
| Term.simplify(ArrayList, AllMyFunction) | 6.0 | 1.0 | 5.0 | 5.0 |
| Term.setFactors(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.sameAs() | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.multTerm(Term) | 2.0 | 1.0 | 3.0 | 3.0 |
| Term.hasNumber() | 3.0 | 3.0 | 1.0 | 3.0 |
| Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.combine() | 27.0 | 7.0 | 13.0 | 13.0 |
| Term.buildNewFactor(Lexer) | 7.0 | 1.0 | 7.0 | 7.0 |
| Term.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SumFunctionFactor.turnString() | 0.0 | 1.0 | 1.0 | 1.0 |
| SumFunctionFactor.SumFunctionFactor(Lexer) | 7.0 | 1.0 | 6.0 | 6.0 |
| SumFunctionFactor.simplify(AllMyFunction) | 38.0 | 1.0 | 9.0 | 14.0 |
| SimpleFactor.turnStringSpecial() | 3.0 | 3.0 | 2.0 | 3.0 |
| SimpleFactor.turnString() | 4.0 | 4.0 | 3.0 | 4.0 |
| SimpleFactor.toString() | 4.0 | 4.0 | 3.0 | 4.0 |
| SimpleFactor.simplify(AllMyFunction) | 2.0 | 2.0 | 1.0 | 2.0 |
| SimpleFactor.SimpleFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| SimpleFactor.setPow(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.sameAs(SimpleFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| NumberFactor.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
| NumberFactor.simplify(AllMyFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setSysmbol(boolean) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setNumber(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.sameAs(NumberFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.NumberFactor(Lexer) | 7.0 | 1.0 | 5.0 | 6.0 |
| NumberFactor.multNumber(BigInteger, boolean) | 1.0 | 1.0 | 1.0 | 2.0 |
| NumberFactor.isSysmbol() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.getNumber() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.compareTo(NumberFactor) | 6.0 | 4.0 | 4.0 | 6.0 |
| NumberFactor.addNumber(BigInteger, boolean) | 6.0 | 1.0 | 4.0 | 4.0 |
| NumberFactor.add(NumberFactor) | 6.0 | 1.0 | 4.0 | 4.0 |
| Main.main(String[]) | 1.0 | 1.0 | 2.0 | 2.0 |
| Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.next() | 12.0 | 3.0 | 8.0 | 10.0 |
| Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getPos() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getNumber() | 2.0 | 1.0 | 3.0 | 3.0 |
| Lexer.getFunction() | 7.0 | 3.0 | 3.0 | 6.0 |
| Lexer.getExpression() | 6.0 | 3.0 | 3.0 | 5.0 |
| Lexer.deleteSpace() | 4.0 | 3.0 | 3.0 | 3.0 |
| Lexer.addOrSub() | 7.0 | 5.0 | 3.0 | 5.0 |
| FunctionFactor.turnString() | 0.0 | 1.0 | 1.0 | 1.0 |
| FunctionFactor.simplify(AllMyFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| FunctionFactor.FunctionFactor(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
| Function.use(String[]) | 14.0 | 5.0 | 5.0 | 6.0 |
| Function.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
| Function.Function(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Expression.turnString() | 4.0 | 3.0 | 4.0 | 4.0 |
| Expression.toString() | 4.0 | 3.0 | 4.0 | 4.0 |
| Expression.simplify(AllMyFunction) | 1.0 | 1.0 | 2.0 | 2.0 |
| Expression.multExpression(Expression) | 3.0 | 1.0 | 3.0 | 3.0 |
| Expression.getTerms() | 0.0 | 1.0 | 1.0 | 1.0 |
| Expression.Expression(Lexer) | 1.0 | 1.0 | 2.0 | 2.0 |
| Expression.combine() | 8.0 | 4.0 | 5.0 | 5.0 |
| Expression.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| ComplexFactor.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
| ComplexFactor.simplify(AllMyFunction) | 2.0 | 2.0 | 2.0 | 3.0 |
| ComplexFactor.getExpression() | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.ComplexFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| AllMyFunction.turnFunction(String) | 7.0 | 1.0 | 6.0 | 6.0 |
| AllMyFunction.findFunction(String) | 3.0 | 3.0 | 2.0 | 3.0 |
| AllMyFunction.addFunction(Function) | 0.0 | 1.0 | 1.0 | 1.0 |
| Total | 323.0 | 156.0 | 230.0 | 274.0 |
| Average | 3.939 | 1.902 | 2.805 | 3.341 |
BUG分析:
第二次作业强测出现了一个BUG。由于第二次作业第一次引入三角函数的化简,并且限制了三角函数内只能有数字和幂函数,单纯的用Factor来抽象三角函数内的内容不太合理(Factor接口中含有表达式因子,不在规定的范围内)。而使用数字因子和幂函数因子抽象三角函数内的内容势必带来大量的判断,比如在构造的时候需要判断里面到底是数字还是幂函数等问题……在一连串的if、else之中,我少判断了一种情况,导致强侧被疯狂hack。

我们通过上面的方法复杂度分析也可以看出,TrigonometricFunction.TrigonometricFunction(Lexer)方法复杂度最高,归根结底是搭建代码框架的时候将太多的功能耦合到这一个方法中去了。
第三次作业
程序结构:
需求简介:
通过对包含加减乘除乘方以及简单三角函数、自定义函数和求和函数的表达式结构进行建模,完成多项式的括号展开与函数调用、化简,输出不带有括号的恒等表达式。
代码架构:
代码的UML图如下:

程序规模和复杂度分析:
类复杂度分析:
| OCarg | OCmax | WMC | |
|---|---|---|---|
| FunctionFactor | 1.0 | 1.0 | 3.0 |
| Main | 2.0 | 2.0 | 2.0 |
| SimpleFactor | 2.125 | 3.0 | 17.0 |
| TrigonometricFunction | 2.2 | 5.0 | 22.0 |
| NumberFactor | 2.308 | 6.0 | 30.0 |
| ComplexFactor | 2.6 | 5.0 | 13.0 |
| Function | 2.667 | 6.0 | 8.0 |
| Expression | 2.875 | 5.0 | 23.0 |
| AllMyFunction | 3.0 | 5.0 | 9.0 |
| Lexer | 3.667 | 10.0 | 33.0 |
| Term | 4.8125 | 13.0 | 77.0 |
| SumFunctionFactor | 6.667 | 14.0 | 20.0 |
| Total | 257.0 | ||
| Average | 3.134 | 6.25 | 21.417 |
方法复杂度分析:
| CogC | ev(G) | iv(G) | v(G) | |
|---|---|---|---|---|
| TrigonometricFunction.turnStringSpecial() | 1.0 | 2.0 | 1.0 | 2.0 |
| TrigonometricFunction.turnString() | 3.0 | 3.0 | 1.0 | 3.0 |
| TrigonometricFunction.tryCombine(TrigonometricFunction) | 2.0 | 2.0 | 1.0 | 2.0 |
| TrigonometricFunction.TrigonometricFunction(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| TrigonometricFunction.toString() | 3.0 | 3.0 | 1.0 | 3.0 |
| TrigonometricFunction.simplify(AllMyFunction) | 9.0 | 5.0 | 5.0 | 5.0 |
| TrigonometricFunction.setPow(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.compareTo(TrigonometricFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| TrigonometricFunction.combine(TrigonometricFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.turnStringSpecial() | 4.0 | 4.0 | 2.0 | 4.0 |
| Term.turnString() | 13.0 | 6.0 | 9.0 | 11.0 |
| Term.tryCombine(Term) | 2.0 | 2.0 | 1.0 | 2.0 |
| Term.toString() | 13.0 | 6.0 | 9.0 | 11.0 |
| Term.termCombine(Term) | 9.0 | 3.0 | 6.0 | 7.0 |
| Term.Term(Lexer) | 3.0 | 1.0 | 4.0 | 4.0 |
| Term.sortFactors() | 5.0 | 1.0 | 4.0 | 4.0 |
| Term.simplify(ArrayList, AllMyFunction) | 8.0 | 1.0 | 6.0 | 6.0 |
| Term.setFactors(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.sameAs() | 1.0 | 1.0 | 2.0 | 2.0 |
| Term.multTerm(Term) | 2.0 | 1.0 | 3.0 | 3.0 |
| Term.hasNumber() | 3.0 | 3.0 | 1.0 | 3.0 |
| Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
| Term.combine() | 27.0 | 7.0 | 13.0 | 13.0 |
| Term.buildNewFactor(Lexer) | 7.0 | 1.0 | 7.0 | 7.0 |
| Term.addFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SumFunctionFactor.turnString() | 0.0 | 1.0 | 1.0 | 1.0 |
| SumFunctionFactor.SumFunctionFactor(Lexer) | 7.0 | 1.0 | 6.0 | 6.0 |
| SumFunctionFactor.simplify(AllMyFunction) | 38.0 | 1.0 | 9.0 | 14.0 |
| SimpleFactor.turnStringSpecial() | 3.0 | 3.0 | 2.0 | 3.0 |
| SimpleFactor.turnString() | 3.0 | 3.0 | 2.0 | 3.0 |
| SimpleFactor.toString() | 3.0 | 3.0 | 2.0 | 3.0 |
| SimpleFactor.simplify(AllMyFunction) | 2.0 | 2.0 | 1.0 | 2.0 |
| SimpleFactor.SimpleFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| SimpleFactor.setPow(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.sameAs(SimpleFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| SimpleFactor.getPow() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| NumberFactor.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
| NumberFactor.simplify(AllMyFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setSysmbol(boolean) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.setNumber(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.sameAs(NumberFactor) | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.NumberFactor(Lexer) | 7.0 | 1.0 | 5.0 | 6.0 |
| NumberFactor.multNumber(BigInteger, boolean) | 1.0 | 1.0 | 1.0 | 2.0 |
| NumberFactor.isSysmbol() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.getNumber() | 0.0 | 1.0 | 1.0 | 1.0 |
| NumberFactor.compareTo(NumberFactor) | 6.0 | 4.0 | 4.0 | 6.0 |
| NumberFactor.addNumber(BigInteger, boolean) | 6.0 | 1.0 | 4.0 | 4.0 |
| NumberFactor.add(NumberFactor) | 6.0 | 1.0 | 4.0 | 4.0 |
| Main.main(String[]) | 1.0 | 1.0 | 2.0 | 2.0 |
| Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.next() | 12.0 | 3.0 | 8.0 | 10.0 |
| Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getPos() | 0.0 | 1.0 | 1.0 | 1.0 |
| Lexer.getNumber() | 2.0 | 1.0 | 3.0 | 3.0 |
| Lexer.getFunction() | 7.0 | 3.0 | 3.0 | 6.0 |
| Lexer.getExpression() | 6.0 | 3.0 | 3.0 | 5.0 |
| Lexer.deleteSpace() | 4.0 | 3.0 | 3.0 | 3.0 |
| Lexer.addOrSub() | 7.0 | 5.0 | 3.0 | 5.0 |
| FunctionFactor.turnString() | 0.0 | 1.0 | 1.0 | 1.0 |
| FunctionFactor.simplify(AllMyFunction) | 0.0 | 1.0 | 1.0 | 1.0 |
| FunctionFactor.FunctionFactor(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
| Function.use(String[]) | 14.0 | 5.0 | 5.0 | 6.0 |
| Function.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
| Function.Function(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Expression.turnString() | 4.0 | 3.0 | 4.0 | 4.0 |
| Expression.toString() | 4.0 | 3.0 | 4.0 | 4.0 |
| Expression.simplify(AllMyFunction) | 2.0 | 1.0 | 3.0 | 3.0 |
| Expression.multExpression(Expression) | 3.0 | 1.0 | 3.0 | 3.0 |
| Expression.getTerms() | 0.0 | 1.0 | 1.0 | 1.0 |
| Expression.Expression(Lexer) | 1.0 | 1.0 | 2.0 | 2.0 |
| Expression.combine() | 8.0 | 4.0 | 5.0 | 5.0 |
| Expression.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.turnString() | 2.0 | 2.0 | 2.0 | 2.0 |
| ComplexFactor.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
| ComplexFactor.simplify(AllMyFunction) | 5.0 | 4.0 | 4.0 | 5.0 |
| ComplexFactor.getExpression() | 0.0 | 1.0 | 1.0 | 1.0 |
| ComplexFactor.ComplexFactor(Lexer) | 4.0 | 1.0 | 3.0 | 3.0 |
| AllMyFunction.turnFunction(String) | 7.0 | 1.0 | 6.0 | 6.0 |
| AllMyFunction.findFunction(String) | 3.0 | 3.0 | 2.0 | 3.0 |
| AllMyFunction.addFunction(Function) | 0.0 | 1.0 | 1.0 | 1.0 |
| Total | 307.0 | 158.0 | 225.0 | 266.0 |
BUG分析:
第三次作业我出现了一个tle的bug。本身在本地测试的时候我的确发现了一些测试点跑的比较慢,当时以为是电脑的问题,中测也是顺利通过,于是我也没有深究。尽管进行了bug修复,但是我的代码任然需要优化。在上面的方法复杂度分析中,很明显有几个方法的复杂度很高。
Term.combine()和SumFunctionFactor.simplify(AllMyFunction)这两个方法在所有方法中复杂度最高,而后者由于在程序中出现的次数较少,也不会对程序有过大的影响。然而Term.combine()方法是我的基础方法之一,每一个项经过化简之后都需要调用这个方法,甚至很多别的方法也直接引用了这个方法,这使这个方法的性能大大影响了我的代码的性能。
四、测试策略
由于笔者能力有限,没有独立完成测评机的能力,只能通过人力进行debug。为了覆盖所有可能的情况,我采用递归的方式构造测试数据。首先,我们有一套完善的表达式形式化描述。(以下拿第一次作业举例)
表达式 → 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项
项 → [加减 空白项] 因子 | 项 空白项 * 空白项 因子
因子 → 变量因子 | 常数因子 | 表达式因子
变量因子 → 幂函数
常数因子 → 带符号的整数
表达式因子 → '(' 表达式 ')' [空白项 指数]
幂函数 → 'x' [空白项 指数]
指数 → '**' 空白项 带符号的整数
带符号的整数 → [加减] 允许前导零的整数
允许前导零的整数 → (0|1|2|…|9){0|1|2|…|9}
空白项 → {空白字符}
空白字符 →
`(空格) |\t`加减 → '+' | '-'
有了形式化描述,构造测试数据就稍微有了眉目。首先找到形式化描述中最基础的元素,也就是除表达式因子以外的因子。构造几个易错的、容易被忽略的因子。

有了最基础的因子,就可以顺着形式化描述往上构造:

好了,测试数据已经开始向离谱的方向发展了,如果往上再构造一层:

将才获得的表达式加入到因子之中,再迭代一次,获得带有一层括号的表达式:

通过这种方式多次构造,即可获得一些较为复杂的测试数据。以普遍理性而论,通过这种方式能概括到所有可能的输入情况,但是人力终究有限。在第一次作业中,我通过这种方式充分测试,找到了程序的bug。但是对于第二次和第三次作业,输入的复杂度急速增加,这种测试方式的局限性也体现了出来,我无法在有限的时间内构造充分的测试数据集导致测试不充分。
五、心得体会

浙公网安备 33010602011771号