本次作業中的規格實現我採取了巨集觀到具體、增量修改 (改不了就重構)
的策略,大致進行以下幾個步驟。
1.首先瀏覽整體某個類中所儲存的資料和需要實現的方法,梳理方法的大致含義以及方法與資料儲存之間的關係。
2.找到幾個比較複雜 (一般是jml很長)
的方法,現根據規格給出的方法大體實現一遍,計算複雜度。
3.若複雜度過高,則嘗試優化,可通過增加儲存資料或優化演算法的方法進行優化,若需要增加儲存資料,則在第2步進行完成後重複第1步。
4.對於非新增的方法,利用文字比對工具篩選出不同的地方,對整體實現的關係進行修正。
5.具體實現,先實現丟擲異常的部分,再實現正常處理的部分,先易後難。
本單元的作業通過jml給出規格,而不需要自己設計架構,因此**不會出現千奇百怪的現象。
首先是分析jml給出的規格有沒有資料型別導致的問題,比如querygroupagevar()
方法中使用的mean是乙個int型別,這裡int型與實際的平均值有一定的差距,因此最終結果可能會出現差距。
其次分析複雜度,對於可能出現 複雜度的jml規格,檢視**,如果同樣出現 的實現方式,就會出現問題。
本單元的方式主要是通過這種方式與其他同學對拍進行測試。
通過python或c語言隨機生成資料,由於考慮到id帶來的一些影響 (隨機生成的id重複率實在感人)
,因此將查詢指令分為正常資料和異常資料,正常資料需要對已經生成的id進行處理,異常資料採用隨機生成的方式,實際上是偽異常資料(因為可能隨機生成的id恰好與已生成的id相同)。
按照從底層到頂層,對簡單和已經確定沒有問題的方法不需要進行測試的思路進行單元測試的編寫和測試,大大減少了測試所用的時間,降低了測試的複雜性。
這乙個單元我使用的容器比較多,包括arraylist、linkedlist、hashmap、hashset,使用策略如下。
1.需要按次序進行儲存,經常進行按索引查詢,但是不需要經常進行新增和刪除的使用arraylist。
2.需要按次序進行儲存,經常進行增刪,且查詢主要存在於頭部的使用linkedlist。
4.不需要按次序進行儲存,主要查詢存在性的使用hashset。
本單元的主要問題出現在效能方面,而效能問題可能出現的地方主要在各種資料的統計方面 (尤其是按照jml給出的方法直接書寫得到複雜度o(n^2)的地方)
。iscircle()
實際上是分析圖中的兩個點是否連通,這裡主要是存在演算法問題,在這裡通過使用並查集的方法進行查詢會即位方便。 (雖然會出現刪除某乙個點導致複雜度**性提高,但並沒有找到合適的解決方案)
queryblocksum()
是使用iscircle()
的方法,實際上是計算圖中的連通分量的個數。但是這裡出現了高複雜度的問題,假設iscircle()
的複雜度為o(1),則queryblocksum()
複雜度為o(n^2),因此我採用了在修改圖過程中維護連通分量個數的方法,降低了複雜度。
這個方法實際上是計算某乙個圖的所有路徑的權重之和的2倍,在這裡同樣採用了修改過程中維護的方法進行降低複雜度,涉及到以下方法。
4.2.1addtogroup() / delfromgroup()
在這裡可以認為是需要增刪某個點,在這裡需要對這乙個點的鄰接路徑進行遍歷,進行增刪。
4.2.2addrelation()
在這個方法可以認為是增加某一條路徑,僅需要增加兩倍的權重即可。
在這個方法中沒有涉及到類似於delrelation()
的方法,但是應類似於addrelation()
方法的處理即可。
querygroupagemean()
方法是計算圖中每乙個點的年齡的平均值,querygroupagevar()
方法是計算圖中每乙個點的年齡的(偽)
方差。相比較於便歷,同樣採用修改圖時進行相關資料的修正的方法。
這乙個方法實際上是查詢兩個點之間的最短加權路徑,主要問題是演算法問題。
在本單元的作業中使用了堆優化dijkstra演算法進行優化。
本次作業由jml給出了規格,因此基本上不需要自己實現架構,因此本部分主要對容器選擇和方法實現方式進行分析。
5.1.1 容器選擇
5.2.2 並查集
本次作業中對圖的操作主要可以採用並查集的方法進行降低複雜度。
由於增加圖中某個點或增加點之間的路徑必然會以某種次序進行,因此可以採用類似於findroot的方法進行記錄。
當增加關係的時候,查詢兩個點的root結點,若結點不相同,則使其中乙個結點的root定位為另乙個root結點即可。
在第一次作業的基礎上新增group和message介面,容易出錯的地方就在於valuesum、agemean、agevar這三個變數,對其進行分別的預處理,詳細操作可詳見4.2、4.3。
第三次作業的難點在於加權最短路徑的計算,在本次作業使用了堆優化dijkstra演算法(非堆優化dijkstra演算法仍有o(n^2)的複雜度)。
private int dijkstra(int personid1, int personid2)hascheck.add(personid);
person person = getperson(personid);
map acquaintance = ((myperson) person).getacquaintance();
for (integer itemid : acquaintance.keyset()) }}
return dismap.get(personid2);
}
新建立的pair類是為了優先佇列進行排序時按照我們所需要的規則進行相應的排序。
在第一次作業中,我根據jml規格直接完成了queryblocksum()
方法,直接導致ctle……
所以jml規格只是規定了這乙個方法在什麼條件下需要幹什麼,不考慮其效能代價,所以需要在這個基礎上進行自己的優化。
(另外,想說一句jml在容器裡刪除或增加某個資料,寫起來真麻煩呃……)
第三次作業在自己本地寫的時候掉進了這個坑……
如果按照c語言理解的話,增刪過程中會出現類似於指標丟失的情況,因此會出現類似於nullpointexception
的異常情況。
課程組給出的指導書還是相對來說比較全面的(雖然增增刪刪好多次)
,但是無法要求所有的jml規格總是如此全面(架構師也可能想不了這麼全面)
,所以我們需要在jml規格的基礎上進行整體認知,至少知道這個類,這個方法需要我們做什麼,不然很有可能出現奇奇怪怪的bug,以及自己編寫過程中一些難以考慮到的地方。
BUAA OO 第三單元總結
一句話概括一下就是 先理解再動手,先實現再優化。首先肯定是要仔細閱讀所提供的jml規格,充分理解規格的作用和其需要完成的任務,在動手之前也先想好要用到什麼內容 選用什麼容器啦,要用什麼資料啦,需不需要修改原本的資料等等 這一點無可厚非。第二步就是先試著動動手,暫不考慮效能以及該規格與原有內容之間的內...
BUAA OO 第三單元總結
本單元主要學習根據課程組提供的介面中的jml規格,實現自己的方法。jml是一種形式化的 面向j a的行為介面規格語言,起初會比較陌生,但是在熟悉後還是比較直白易懂的,而且比較直接也非常詳細地給出了思路,當然了,本次作業中有許多處的容器和資料結構是需要自己設計和優化的。這也是三次作業主要的工作量。不過...
BUAA OO 第三單元作業總結
本單元作業由於設計架構已經基本規定好,只需要實現部分介面的功能即可,所以歷次作業的實現幾乎相同,都遵循以下幾個步驟 閱讀指導書,先大體梳理一遍需要實現的是哪些部分 閱讀jml整體規格,關注當前介面對應的類需要維護哪些屬性以及該類的規格大小,並大體閱讀一下有哪些方法以選擇適當的容器 細讀jml規格,先...