OO2022第一单元个人总结
OO2022第一单元个人总结
第一单元的作业主要是实现表达式化简,第二次作业加入了三角函数和函数调用,第三次作业中加入了括号嵌套,总体来讲难度不大,都可以分为建树,表达式化,化简三个步骤,下面将逐一进行介绍。(顺便一提 starUML真不好用 个人强烈建议使用mermaid这种轻量化的UML工具 以下的所有类图均为mermaid作图
1.第一次作业
第一次作业主要针对只含有单层括号的简单多项式进行化简拆括号,最终化简出来的表达式一定以多个幂函数和的形式存在,所以只需将表达式中的每一项都多项式化存在一个List内,最终以加号连接并输出即可
1.1数据结构
数据结构的相关构造参考了讨论区强生同学的帖子,将整体结构分为两个部分,一是建树,而是多项式化,为了得到清晰的树结构分别定义了Expr,Term,Factor三个类,Expr中的每个Term均以加号连接,Term中的每个Factor均以乘号连接。
第一次作业的文法中Factor只有表达式因子、变量因子、常数因子三种类型,故将因子设计为接口类型,所有因子都有一个getRepe用来返回表达式因子的指数,因为在处理表达式因子的幂次时把他直接拆开成n个底数的乘积能更好的进行多项式化简的处理。
Lexer类主要用于递归下降过程中检索每次扫描到的内容,Parser类用于建立整体树结构,为了保证Parser类有较好的拓展性,直接为每个非终结符都建立一个parser方法,同时将文法改写为左递归文法方便parser的构筑,事实上本单元文法并不需要超前读这种操作,所以直接使用吴佬提供的样例程序完全够用。
由于最终的表达式一定是以多个\(ax^i\)相加的形式存在,所以直接定义PolyItem来表示,同时定义Polynomial对PolyItem进行存储和化简,第一次作业本身只涉及底数相同的PolyItem的化简,所以直接将指数作为Hashmap的键,只要指数相同就直接化简即可。
整体来看本次作业在设计上具有较好的拓展性,同时为后边的作业预留了很多更新空间,不用进行重构等操作,但是仍然出现了部分static方法,这确实是当时写代码时的思路漏洞。
1.2代码结构分析
Source File | Total Lines | Source Code Lines | Source code Lines [%] | Comment Lines | Comment Lines [%] | Blank Lines | Blank Lines [%] |
---|---|---|---|---|---|---|---|
Expr.java | 59 | 47 | 0.7966101694915254 | 1 | 0.01694915254237288 | 11 | 0.1864406779661017 |
Factor.java | 9 | 6 | 0.6666666666666666 | 0 | 0.0 | 3 | 0.3333333333333333 |
Lexer.java | 43 | 36 | 0.8372093023255814 | 0 | 0.0 | 7 | 0.16279069767441862 |
Main.java | 24 | 20 | 0.8333333333333334 | 1 | 0.041666666666666664 | 3 | 0.125 |
Number.java | 36 | 27 | 0.75 | 1 | 0.027777777777777776 | 8 | 0.2222222222222222 |
Parser.java | 143 | 127 | 0.8881118881118881 | 0 | 0.0 | 16 | 0.11188811188811189 |
PolyItem.java | 63 | 52 | 0.8253968253968254 | 0 | 0.0 | 11 | 0.1746031746031746 |
Polynomial.java | 106 | 94 | 0.8867924528301887 | 1 | 0.009433962264150943 | 11 | 0.10377358490566038 |
Term.java | 54 | 44 | 0.8148148148148148 | 1 | 0.018518518518518517 | 9 | 0.16666666666666666 |
Var.java | 53 | 41 | 0.7735849056603774 | 1 | 0.018867924528301886 | 11 | 0.20754716981132076 |
method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
poly.PolyItem.toString() | 9.0 | 5.0 | 3.0 | 5.0 |
parser.Parser.parseExprFactor() | 8.0 | 1.0 | 5.0 | 5.0 |
parser.Parser.parseTerm(String) | 8.0 | 1.0 | 4.0 | 6.0 |
poly.Polynomial.mergePoly() | 8.0 | 1.0 | 6.0 | 6.0 |
lex.Lexer.next() | 4.0 | 2.0 | 3.0 | 4.0 |
parser.Parser.parseExpr() | 4.0 | 1.0 | 5.0 | 5.0 |
parser.Parser.parseVarFactor() | 4.0 | 1.0 | 4.0 | 4.0 |
expr.Term.toString() | 3.0 | 1.0 | 3.0 | 3.0 |
parser.Parser.parseFactor() | 3.0 | 3.0 | 3.0 | 3.0 |
poly.Polynomial.toString() | 3.0 | 1.0 | 3.0 | 3.0 |
expr.Var.toString() | 2.0 | 2.0 | 1.0 | 2.0 |
lex.Lexer.getNumber() | 2.0 | 1.0 | 3.0 | 3.0 |
parser.Parser.parseBracket() | 2.0 | 1.0 | 3.0 | 3.0 |
parser.Parser.parseNum() | 2.0 | 1.0 | 3.0 | 3.0 |
expr.Expr.toPolynomial() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Expr.toString() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Term.addFactor(Factor) | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Term.toPolynomial() | 1.0 | 1.0 | 2.0 | 2.0 |
Main.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.Expr() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getTerms() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.Number(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.getNum() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.toString() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.Term() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.Var() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Var.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
parser.Parser.Parser(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
parser.Parser.parseNumberFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.PolyItem(String, BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.PolyItem(String, BigInteger, int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getCoe() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setCoe(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.Polynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addAllPolyItem(Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addPoly(Polynomial, Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addPolyItem(PolyItem) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.getPolyItems() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.setPolyItems(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
Total | 76.0 | 65.0 | 102.0 | 108.0 |
Average | 1.3333333333333333 | 1.1403508771929824 | 1.7894736842105263 | 1.894736842105263 |
从数据项中可以看出,大部分代码的耦合度都比较低,Parser类中由于使用递归下降的方法可能出现了部分方法复杂度较高的问题,但总体来看由于第一次作业不涉及复杂文法和复杂化简,代码结构整体上还是比较好的,但是为了避免敏感问题导致注释过少的问题确实是个缺陷。
1.3bug修复
第一次作业文法较为简单,测试数据也比较喜人,故在中强测中没有出现过bug,互测中倒是出现了一个不小的bug,就是所有输入加空格的形式都无法解析,因为一开始我担心后续会出现抛文法异常的要求,所以没有简单的将所有空格替换掉,而是在parser中加入了parseBracket方法来处理空白项,但是却在parseExpr中少处理了一个空格,于是在Parser类里删掉了这个方法并在main中将所有空格替换掉,就解决了问题,只能说互测被扣的分略有些尴尬..
互测中还出现了爆栈的问题,比如(90) ** 30这种测试数据,主要特征就是指数特别大,发现是在Polynomial的multi方法里出了问题,应该每添加一项就去化简一次而不是囤起来再化简,在方法末尾加了一行merge后bug就消失了。
2.第二次作业
第二次作业加入了三角函数和函数调用,函数调用比较容易处理,在函数定义的时候用Hashmap把名字和函数内容存了,递归下降分析时每读到一个函数名就直接去hashmap里面找,并将所有形参替换掉,继续进行递归调用即可,我个人在这里犯了个懒,采用了字符串替换的策略,后面被人hack惨了,只能说这种方法轻易不要采用,一定会有疏漏的地方的,至于三角函数,其本身涉及了一些比较复杂的内容,多项式化和化简的策略都需要重新进行构筑。
2.1数据结构
第二次作业中变量因子作为一个非终结符出现,故新定义Var类作为所有变量因子的父类,并新定义幂函数类(Power)三角函数类(Trigono)求和函数类(SumFunction)自定义函数类(MyFunction),在Parser中根据递归下降读取到的字符来进行判断factor的具体构造类型,读到‘(’就判断为表达式因子,读到字母就判断是变量因子随后再根据字母的具体内容进行判断,否则就是普通常数类。
FuncDefine类用来存储函数定义,并定义了形参替换的方法,具体实现方式为分别将形参的字符串替换为对应实参并加上一个括号,同时为了防止误判,这里的替换方式是分别将形参替换为占位符在替换为实参,比如把x换成¥1,y换成¥2,再进行实参的替换。
由于无法再将多项式中的每个项单纯抽象为\(ax^i\),故将PolyItem类作为父类,新构建了三个类来表示对每一项的抽象,分别是单独的普通项(SinglePolyItem),单独的三角函数项(SinglePolyTrigono),复杂项(MultiPolyItem),对于仍然能抽象成\(ax^i\)的项就将其定义为SinglePolyItem,如幂函数和常数,对于只包含单独的三角函数的项将其定义为SinglePolyTrigono,对于像xcos(x),xyz,cos(x)sin(x)之类的项将其定义为multiPolyItem,在后期进行化简的时候直接根据各个项的类型进行化简,进行分类讨论即可。
Tool类是用于输出java运行栈内容的函数,方便我进行查找哪部分调用了什么内容,属于个人debug用的一个简易工具(其实是懒得按stepinto。
2.2代码结构分析
Source File | Total Lines | Source Code Lines | Source code Lines [%] | Comment Lines | Comment Lines [%] | Blank Lines | Blank Lines [%] |
---|---|---|---|---|---|---|---|
Expr.java | 60 | 47 | 0.7833333333333333 | 2 | 0.03333333333333333 | 11 | 0.18333333333333332 |
Factor.java | 9 | 6 | 0.6666666666666666 | 0 | 0.0 | 3 | 0.3333333333333333 |
FuncDefine.java | 85 | 67 | 0.788235294117647 | 3 | 0.03529411764705882 | 15 | 0.17647058823529413 |
Lexer.java | 63 | 52 | 0.8253968253968254 | 1 | 0.015873015873015872 | 10 | 0.15873015873015872 |
Main.java | 46 | 38 | 0.8260869565217391 | 2 | 0.043478260869565216 | 6 | 0.13043478260869565 |
MultiPolyItem.java | 134 | 120 | 0.8955223880597015 | 1 | 0.007462686567164179 | 13 | 0.09701492537313433 |
MyFunction.java | 106 | 85 | 0.8018867924528302 | 5 | 0.04716981132075472 | 16 | 0.1509433962264151 |
Number.java | 36 | 27 | 0.75 | 1 | 0.027777777777777776 | 8 | 0.2222222222222222 |
Parser.java | 248 | 226 | 0.9112903225806451 | 3 | 0.012096774193548387 | 19 | 0.07661290322580645 |
PolyItem.java | 42 | 31 | 0.7380952380952381 | 0 | 0.0 | 11 | 0.2619047619047619 |
Polynomial.java | 242 | 221 | 0.9132231404958677 | 3 | 0.012396694214876033 | 18 | 0.0743801652892562 |
Power.java | 53 | 41 | 0.7735849056603774 | 1 | 0.018867924528301886 | 11 | 0.20754716981132076 |
SinglePolyItem.java | 64 | 54 | 0.84375 | 0 | 0.0 | 10 | 0.15625 |
SinglePolyTrigono.java | 81 | 68 | 0.8395061728395061 | 0 | 0.0 | 13 | 0.16049382716049382 |
SumFunction.java | 82 | 67 | 0.8170731707317073 | 0 | 0.0 | 15 | 0.18292682926829268 |
Term.java | 54 | 44 | 0.8148148148148148 | 1 | 0.018518518518518517 | 9 | 0.16666666666666666 |
Tool.java | 12 | 9 | 0.75 | 0 | 0.0 | 3 | 0.25 |
Trigono.java | 61 | 49 | 0.8032786885245902 | 0 | 0.0 | 12 | 0.19672131147540983 |
Var.java | 26 | 20 | 0.7692307692307693 | 0 | 0.0 | 6 | 0.23076923076923078 |
Total: | 1504 | 1272 | 0.8457446808510638 | 23 | 0.015292553191489361 | 209 | 0.1389627659574468 |
method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
poly.Polynomial.mergePoly() | 23.0 | 1.0 | 11.0 | 11.0 |
poly.MultiPolyItem.mergePoly() | 18.0 | 6.0 | 10.0 | 11.0 |
parser.Parser.parseSumFactor() | 15.0 | 1.0 | 6.0 | 6.0 |
poly.Polynomial.multiplyTrigonoPoly(PolyItem, PolyItem) | 13.0 | 1.0 | 7.0 | 7.0 |
poly.SinglePolyItem.toString() | 13.0 | 1.0 | 7.0 | 7.0 |
parser.Parser.parseFuncDefine() | 11.0 | 1.0 | 6.0 | 6.0 |
parser.Parser.parseTriFactor() | 11.0 | 1.0 | 6.0 | 6.0 |
poly.MultiPolyItem.toString() | 10.0 | 1.0 | 6.0 | 6.0 |
poly.Polynomial.multiplyPoly(Polynomial, Polynomial) | 10.0 | 1.0 | 5.0 | 7.0 |
poly.SinglePolyTrigono.toString() | 10.0 | 1.0 | 6.0 | 6.0 |
parser.Parser.parseExprFactor() | 8.0 | 1.0 | 5.0 | 5.0 |
parser.Parser.parseFuncFactor() | 8.0 | 1.0 | 5.0 | 5.0 |
parser.Parser.parseTerm(String) | 8.0 | 1.0 | 4.0 | 6.0 |
expr.FuncDefine.toString() | 5.0 | 3.0 | 1.0 | 3.0 |
expr.var.MyFunction.toPolynomial() | 5.0 | 1.0 | 3.0 | 3.0 |
expr.var.MyFunction.toString() | 5.0 | 3.0 | 3.0 | 3.0 |
lex.Lexer.next() | 5.0 | 2.0 | 4.0 | 5.0 |
parser.Parser.parseVarFactor() | 5.0 | 4.0 | 5.0 | 5.0 |
parser.Parser.parseExpr() | 4.0 | 1.0 | 5.0 | 5.0 |
parser.Parser.parsePowerFactor() | 4.0 | 1.0 | 4.0 | 4.0 |
poly.Polynomial.multiplySinglePoly(PolyItem, PolyItem) | 4.0 | 1.0 | 4.0 | 4.0 |
expr.Term.toString() | 3.0 | 1.0 | 3.0 | 3.0 |
parser.Parser.parseFactor() | 3.0 | 3.0 | 3.0 | 3.0 |
poly.Polynomial.toString() | 3.0 | 1.0 | 3.0 | 3.0 |
expr.var.Power.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
expr.var.Trigono.toString() | 2.0 | 2.0 | 2.0 | 2.0 |
lex.Lexer.getNumber() | 2.0 | 1.0 | 3.0 | 3.0 |
lex.Lexer.getVar() | 2.0 | 1.0 | 3.0 | 3.0 |
parser.Parser.parseNum() | 2.0 | 1.0 | 3.0 | 3.0 |
poly.MultiPolyItem.addPolyItems(PolyItem) | 2.0 | 1.0 | 2.0 | 2.0 |
poly.Polynomial.equals(Object) | 2.0 | 3.0 | 1.0 | 3.0 |
Main.getFunc(ExprInput) | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Expr.toPolynomial() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Expr.toString() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Term.addFactor(Factor) | 1.0 | 1.0 | 2.0 | 2.0 |
expr.Term.toPolynomial() | 1.0 | 1.0 | 2.0 | 2.0 |
expr.var.SumFunction.toPolynomial() | 1.0 | 1.0 | 2.0 | 2.0 |
Main.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.Expr() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.addTerm(Term) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.getTerms() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Expr.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.getDefine() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.getFirstFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.getSecondFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.getThirdFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.setDefine(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.setFirstFactor(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.setSecondFactor(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.setThirdFactor(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.subDefine1(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.subDefine2(String, String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.FuncDefine.subDefine3(String, String, String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.Number(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.getNum() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Number.toString() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.Term() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.Term.getFactors() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getFirstFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getFuncs() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getSecondFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.getThirdFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.setFirstFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.setFuncs(HashMap) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.setSecondFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.MyFunction.setThirdFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.Power() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Power.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getHigh() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getIname() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getLow() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.setFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.setHigh(Number) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.setIname(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.setLow(Number) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.SumFunction.toString() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.getFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.setFactor(Factor) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Trigono.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Var.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Var.getRepe() | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Var.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
expr.var.Var.toPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.Lexer(String) | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.getInput() | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.getPos() | 0.0 | 1.0 | 1.0 | 1.0 |
lex.Lexer.peek() | 0.0 | 1.0 | 1.0 | 1.0 |
parser.Parser.Parser(Lexer) | 0.0 | 1.0 | 1.0 | 1.0 |
parser.Parser.parseNumberFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
parser.Parser.setFuncs(HashMap) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.MultiPolyItem() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.addAllPolyItems(MultiPolyItem) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.getFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.getPolyItems() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.getPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.setPolyItems(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.MultiPolyItem.useAsPolinomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getCoe() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.getPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setCoe(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.PolyItem.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.Polynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addAllPolyItem(Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addPoly(Polynomial, Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.addPolyItem(PolyItem) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.getPolyItems() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.hashCode() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.multiplyMultiPoly(PolyItem, PolyItem) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.Polynomial.setPolyItems(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.SinglePolyItem(String, BigInteger, int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.getCoe() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.setCoe(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyItem.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.SinglePolyTrigono(String, BigInteger, int, Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.getCoe() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.getFactor() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.getPolynomial() | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.setCoe(BigInteger) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.setFactor(Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.setIndex(int) | 0.0 | 1.0 | 1.0 | 1.0 |
poly.SinglePolyTrigono.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
tool.Tool.getFileName() | 0.0 | 1.0 | 1.0 | 1.0 |
tool.Tool.getLineNumber() | 0.0 | 1.0 | 1.0 | 1.0 |
Total | 224.0 | 173.0 | 267.0 | 277.0 |
Average | 1.4545454545454546 | 1.1233766233766234 | 1.7337662337662338 | 1.7987012987012987 |
由于多项式项的抽象程度变差了些,merge方法的复杂度明显比第一次作业高了不少,而且Polynomial和MultiPolyItem的merge方法的复杂度都非常高,可见代码方面还有很多需要优化的地方和重构的地方,秉持着啃屎山不重构的后端从业者态度,这一星期的代码确实蛮烂的。
2.3bug修复
这一周的bug一方面集中在Polynomial类的multi方法merge方法,和MultiPolyItem的merge方法内,都有比较明显的特征即频繁出现了常数0但输出时却忽略了0的影响,于是在所有merge方法和muti方法中,我对指数0 系数0 三角函数内的因子为0都进行了特判,虽然解决了问题但是代码行数急剧上升。
另一方面集中在字符串替换的问题,主要产生在SumFunction类的toPoynomial方法中和MyFunction类的toPolynomial方法中,特征集中的表现为进行字符串替换后解析时发现不符合文法导致re,最后的修复方案就是给所有的替换字符串都打个括号包上,一致地视为其为表达式因子,这些问题才顺利解决了。
由于我在写完这一星期的作业时没有充足的时间来debug,弱测一遍过了我就再没管了,结果就是强测糊了,被hack烂了,仅有24人的c房一周游了,这一周说实话被hack100多刀我都不奇怪,只能说感谢房间的同学们留了一手。
3.第三次作业
第三次作业就是俺修完bug的第二次作业,所以数据结构和代码结构就不再往上放了,直接讲一下bug修复的过程。
第三次作业主要有三处bug,一处是三角函数输出时的格式错误,这个问题产生在SinglePolyTrigo类的toString方法中,由于我对三角函数内的因子进行判断的matcher写的不太好,导致三角函数输出时经常会少带个括号,后面就清一色改成都带个括号输出了。
第二处bug产生在sum中i的取值上,发生在SumFunction类的toPolynomial方法内,我之前忽略了i的取值是BIgInteger的问题,导致我在写循环的时候发生了一些问题,当i的取值大于int范围时就会报错,后面改成for(BigInteger;compareto;add(BigInteger.ONE))就解决了
第三处bug依然是指数0的问题,产生在Polynomial类的multi方法中,对指数0的三角函数和指数0的幂函数同乘时出现了错判导致少了一个输出,修复的时候赶紧改了一下multi的逻辑就解决了。
4.bug分析
通过对比三次作业的bug产生处可发现,大部分bug出现的代码段都具有较高的圈复杂度和较长的代码行数,不得不说得亏方法长度被控制在了60行以内,不然可能会出更多麻烦,从第二次作业开始代码的耦合度就比较高,在多项式化简这里的处理确实还有待提升。
5.hack策略
由于个人时间实在是不够,且对于hack本身不太感兴趣,所以我大概在本学期都不会进行hack行为,不过单就第一单元的情况来看hack策略可以集中的表现在边界值和全覆盖两种方式上,边界值这种就自己捏一个或者直接看代码里面对极限情况的处理方法,目前我被hack的所有数据一般都是这种形式,还有一种全覆盖的策略就是说照着文法去递归的造数据,答案直接调用sympy的库来化简,不断的去对一个程序去测试,测试次数足够多的时候就能接近全覆盖了。
6.架构设计体验
在第一周的作业中主要通过递归下降去建树,并统一进行多项式化来得到最简表达式,但是到了第二周加入了函数调用和三角函数后,发现不能够单纯的将每一项都抽象为同一种结构去构建多项式,于是架构中对不同的多项式项和变量因子也进行了区分,但是整体架构并没有发生太大的变化,依然是递归下降建树和统一进行多项式化两个步骤,而且在第三次作业中甚至不需要改动什么内容就能AC了,可见在代码构造前确定一个拓展性强的架构的重要性,事实上如果手动的去解析树并生成一系列pcode代码(就是手动去搓一个预解析模式)三次作业的类图甚至都不会有太大的变化,想来菁哥哥一直在强调的一定要想好了架构再写真是一句非常重要的话啊。
7.心得体会
首先必须要感谢强生同学讨论区那篇帖子,我从写完递归下降建好树以后就一直在想怎么去统一的处理这些东西,这篇帖子给了我极大的思路,以至于后续的作业我一直在沿用这个架构,感谢强总!
其实本单元对我个人而言不算太难,因为这一单元的内容和编译原理没有太大区别,所以就心得体会而言可能没有太多感触,唯独要说的是这单元寄了的同学们要小心编译课程喔。
再者来讲讲我个人的一些破事,很多学弟学妹来问我为什么19级才上OO是因为重修了吗?俺先宣布个事,我去年就属于是犯懒的那批人,第一周快结束了pre都还没做完,导致我第一周作业寄了,在和吴老师面对面交流了近一个小时后吴老师给了我一个非常中肯的建议,那就是让我去修21系的部分课,这学期先把OO退了,专心搞OS,来年不要再重蹈覆辙,所以在和教务沟通了一番之后我就退了OO课去跟21系学软工和JAVA,就结果来看21系学到的那些知识让我在数据库课程上好好Carry了一把,并且今年的OO课也得心应手了些,OS也有更多时间去思考,唯一的缺点就是我耽误了今年选别的一些课的时间吧。其实说这么多都没什么用,在这里就是想告诉各位学弟学妹,切记不能犯懒,懒了基本就烂了,俺现在实习复习OO三头抓(还好学分早修够了不然更麻烦),时间非常紧迫,这些都是当初犯懒留下的苦果只能硬着头皮啃了,尤其pre没做完的那些同学,一定要注意及时止损。(这届助教团队真的巨强 有问题就快问吧 自己憋着效率不高