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沒做完的那些同學,一定要注意及時止損。(這屆助教團隊真的巨強 有問題就快問吧 自己憋着效率不高