BUAA面向物件2022第一單元總結
總覽
作業內容
本單元的主要作業內容為表示式拆括號,共有3次作業,為迭代開發。
第一次作業只有加減乘次方以及單層括號。
第二次作業加入了巢狀括號,簡單三角函式,自定義函式和求和函式。
第三次作業加入了巢狀三角函式和巢狀自定義函式。
完成情況
我在三次作業中使用了遞迴下降法,堅持迭代開發,沒有進行過重構。
三次均有bug,但是都滿分通過了強測。(這強測是真的弱)
效能分:在第一次作業中獲得滿分,第二三次作業中由於沒有進行足夠的三角優化,扣了不少
互測情況:三次作業 發起/受到hack 分別為 2/12 , 2/3 , 5/3
bug分析
第一次作業:在輸出第一個正項時,如果是常數項,會多輸出一個*
第二次作業:遇到sin(-1)**2時,直接把符號提了出來,即-sin(1)**2
第三次作業:遇到sin(sin(-1))時,會把裡層括號的負號算2次,即sin(sin(1))
純nt
實現過程
總體思路
先將輸入的自定義函式和表示式經過一定的處理,後使用parser和lexer對錶達式進行遞迴下降解析。
利用字串整體替換並加一層括號實現函式的呼叫。
使用兩層HashMap對結果進行儲存,便於合併同類項。
UML類圖
UML類圖解釋
除了介面的實現,我把聯絡緊密的類用直線連了起來。
MainClass:輸入與輸出
ChangeString:去掉空白符以及將多字元的符號(例如**)換成特定單字元符號(例如^),便於lexer和parser解析
Lexer:掃這個表示式
Parser:對錶達式進行遞迴下降,當遇到不同的符號/數字時,執行不同的解析方法。
Expr:表示式,由若干項組成,+
連線,startFh為第一個符號。
Term:項,由若干因子組成,*
連線,包含了startFh為第一個符號。
Factor:因子,分為常數因子,變數因子,三角函式因子,自定義函式因子,求和函式因子,表示式因子。其中getAns()方法會返回化簡後的表示式。
Number:常數因子,由一個常陣列成。
Variable:變數因子,由x
和指陣列成。
SanJiao:三角函式因子,由三角函式型別和內部表示式以及指陣列成。
FindVariable:找出自定義函式和求和函式中由,
ZiDingYi:自定義函式因子,經過替換處理後看作表示式。
Sum:求和函式因子,經過替換處理後看作表示式。
SimpleFactor:化簡後的因子。
Polynomial:化簡後的多項式。
Node:化簡後的三角函式內部的玩意。
這裡對Polynomial和Node進行一些額外的說明。
Polynomial中的第一層HashMap的key值為化簡後的各個項,value為這些項的乘積的係數。
即:(Value:coeff)(Key:*sin(X)^a*...*cos(Y)^b)
第二層HaspMap的key值為某個sin(X)^exp中的X,value為其中的exp
在第二次作業中X一定可以用a*x^b表示,因此我用兩個變數將a,b儲存。
可以發現這樣儲存之後對於Polynomial的運算會很方便。
在第三次作業中,由於X可以是一個Polynomial,但是我發現只需要將Node中的a,b變成一個Numbe/Variable/Polynomial(也就是SimpleFactor)就可以沿用之前的所有運算操作,不需要任何其他的改變。
結果化簡與輸出
對於sin(0)直接返回0,cos(0)返回1。
對於sin內部第一項係數為-,將其內部取反外部加負號。
cos同理,只是外部不加負號。這樣可以消掉一些恰好為相反數的項。
輸出時採用遞迴輸出,對於三角函式,可以判斷其內部是否是一個常數或是一個係數為1的因子,如果是則只用套一層括號。
複雜度分析
程式碼總行數:841
優點:每個類想實現的功能比較清晰,類之間的耦合度較低。
缺點:有些類在實現起來的時候實在是過於醜陋,以至於寫出了bug
可以看到,在方法複雜度中,採用了較多if的方法複雜度較高,事實上我的錯誤也都錯在這些方法。
第一次是Polynomial.toString(),二三次是SanJiao.getAns()。
因此提高程式碼的結構化是降低bug出現概率的重要手段。
總結與反思
程式碼架構
這次我對自己的程式碼整體架構還比較滿意。在第二次到第三次的迭代中,我幾乎沒有進行太多修改就完成了任務。不過這主要還是因為遞迴下降的板子寫的好,如果讓我自己寫,我很可能寫不出來。
當然我也有一些不足,比如搞了ChangeString和FindVariable這兩個奇怪的類,其實我只是為了寫一個靜態方法。還有就是Polynomial的運算實際上只用傳一個引數,我傳了兩個,就看起來很蠢。
關於互測
其實我並沒有認真讀別人的程式碼,只是用了一些看起來容易錯的資料,然後就hack到了一些人。
反思
這三次的bug實在是不應該。雖然都是在優化的時候寫出來的bug,但是bug都非常明顯。這說明我寫程式碼和測試時都不夠認真。
一些建議
可以把效能分最高的結果展示出來。
可以加一些額外任務,例如不合法表示式的判斷,sum函式的巢狀等(作為額外的測試點),這樣卷王們就有更多事情可以去做了。