1. 程式人生 > 其它 >BUAA面向物件2022第一單元總結

BUAA面向物件2022第一單元總結

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函式的巢狀等(作為額外的測試點),這樣卷王們就有更多事情可以去做了。

可以把一些hack成功的資料再給所有人測一遍。