OO第三單元作業總結

2022-09-09 07:15:12 字數 3890 閱讀 6845

​ 在起初剛學習完jml規格語法的時候,由於對jml規格不夠熟練,我選擇了讓自己的**與規格**基本保持一致來完成作業。意思是,jml使用陣列實現,我也會使用陣列實現;jml使用兩層for迴圈實現,我也會使用兩層for迴圈實現。並且,我選擇了每讀乙個方法的jml,就完成乙個方法。

​ 顯然,這樣的策略不會讓我產生結果錯誤,但是問題也很顯然——如果某個方法使用了雙層迴圈巢狀,那根據演算法複雜度分析,我們最高可能會達到o(n^3)的時間複雜度(其實達不到),顯然,針對5000組的互測資料和10000組的強測資料,可能會造成tle。隨著這個問題的發現,我意識到,我不能完全按照jml寫**,我們需要優化。

​ 於是,在第

二、三次作業中,我選擇了先讀完部分jml,比較好實現的類我會先完成;對於複雜的類,我會選擇分步實現,如果發現複雜度可能會為o(n^2)的方法,我會對其做上標記,提醒自己這個方法可能會造成tle,一方面是告訴自己要小心,一方面是可以針對這個方法構造資料來hack。

​ 就這樣,我通過這樣的策略完成了這單元的作業。

​ 說實話,本單元我並沒有使用junit等工具測試,而是依然使用評測機生成隨機資料,通過對拍完成測試。

​ 最開始,我選擇的是陣列。但很顯然,陣列的缺點很明顯,乙個是大小不好確定,這一點可以通過使用arraylist完善;另乙個是查詢的複雜度是o(n),這一點影響很大,讓我放棄了陣列和arraylist的使用,選擇了可以o(1)查詢的hashmap。

​ 而對於map的選擇,中途我和我的同學還討論過hashmap與treemap之間的選擇。由於hashmap可能會有很多衝突,導致退化為o(n)複雜度,而treemap是紅黑樹實現,複雜度穩定在o(logn),所以,我們討論了這次作業哪個容器更加優秀。通過網上搜尋資料,得到以下資料:

​ 所以,我們最終選擇了hashmap。

​ 由於要找出聯通塊的個數,我使用hashset儲存聯通塊的某個特徵量,來得到連通塊個數。但是hashset的插入複雜度也不低,但我覺得影響不大。

​ 由於資料組數最大是5000到10000,所以我們需要控制每個方法總的複雜度在o(nlogn)以內。所以,我們只需要解決規格中複雜度比這個複雜度高的方法即可。

1.第一次作業

​ 我認為第一次作業主要是讓我們熟悉jml規格,主要的優化是將陣列轉化為可以o(1)查詢的hashmap。

​ 其中複雜度最高的,乙個是query_circle,乙個是query_block_sum

​ 這兩個方法,要實現的分別是得到兩個人是否處於乙個關係網中,和連通塊的個數,都是o(n²)以上的複雜度。為了實現這兩個方法,我們可以使用並查集演算法,構造乙個關係網。那麼,前者的複雜度就是o(1),最高可達o(n);後者複雜度是o(n)。而實現這個演算法,最重要的部分是維護這個並查集,這個我們後面再說。

2.第二次作業

​ 本次作業主要有以下方法需要優化。

query_group_age_var:這個方法需要我們得到方差,求平均值的複雜度是o(n),所以求方差的複雜度可能會很高,那麼我們可以通過維護乙個age總和來解決。得到平均值只需要計算年齡總和/人數,複雜度o(1)。計算方差就用普通方法,複雜度o(n)

query_group_value_sum:從規格來看,這個方法的複雜度很高。我們可以通過直接維護value_sum變數來解決這個問題。查詢複雜度為o(1),我們便解決的這個問題。

3.第三次作業

send_indirect_message:顯然,這個方法需要我們求兩人之間的最短路長度,我們可以使用dijkstra演算法優化,將複雜度降至o(nlogn)

1.架構設計

​ 由於是迭代開發,我們每次作業只需要考慮新增的方法即可。由於整體架構jml已經給出,我們要做的就是區域性最優,即每個方法都做到最優,就可以使得整體最優。當然,有的方法想要達到最優,還需要配合其他方法進行資料維護,而維護十分重要。

2.維護策略

​ 對於第一次作業,我們需要維護乙個並查集,涉及的操作有add_personadd_relation。對於前者,我們只需要在hashmap中新增這樣的鍵值即可。對於後者,我們需要做並查集中的merge操作即可。這樣,我們就完成了並查集的維護。

​ 對於第二次作業,我們需要維護age_sumvalue_sum。對於第乙個變數,我們需要在新增刪除人時修改變數即可。對於第二個變數,需要考慮的是,我們在addperson時,需要判斷這個人和group裡其他人是否有關係,如果有,需要對變數進行修改;在add_relation時,我們需要判斷這兩個人是否同時在某乙個group中,如果是,需要對變數進行修改;delperson時,與addperson同理,需要進行維護。維護複雜度為o(n)

​ 對於第三次作業,我們需要維護dijkstra演算法中的邊和頂點。對於頂點,我們只需要在add_person時插入頂點id即可。對於邊,我們需要在add_relation時,新增正反兩條邊,構成無向圖即可。

​ 在完成作業後,我通過測試發現了很多bug。好在我在中測截止前發現並修復了所有bug,沒有出現嚴重的錯誤。三次作業中,我都有一些由於疏忽導致的錯誤,如下文所述。

1.第一次作業

​ 通過並查集計算連通塊個數時,我會將每個節點的根節點放入乙個集合當中,最後計算集合的長度,就可以知道連通塊的個數。但在放入根節點的時候,我只是放入了某個節點的父節點,而未使用find()方法放入根節點,出現了乙個bug。

2.第二次作業

​ 計算方差時,我未考慮group中人數為0的情況,導致觸發了異常。

​ 在動態維護value_sum時,我忘記考慮add_relation指令也需要進行維護。

​ group的人數上限應為1111人,我未增加限制。

3.第三次作業

​ 起初我以為emojiid與其messageid是相同的,導致我在獲取emojiid時都是用的messageid,出現了許多錯誤。

​ 在傳送redenvelopemessage時,person1獲得的錢應該*-1,即他的錢應該減少,而我忘記乘-1。

​ 在寫dijkstra時,忘記使用visited進行標記,導致很小的圖卻需要進行大量次數的迴圈。

​ 這個單元除了讓我們認識了jml規格,還培養了我們對**的分析能力。在讀**的時候,我們需要分析給出jml**的複雜度,並用與jml**效果相同的複雜度更低的**進行實現。

​ 如果不進行部分演算法優化,可能不會掛強測,但是肯定會在互測環節被hack,所以,這個單元在我看來,更像是乙個單元的「演算法課」 acm玩家狂喜 ,對演算法不熟悉的同學可能會十分煩惱,比如沒有聽過學過並查集的同學。

​ 對於測試部分,由於指令集巨大,所以自動生成資料部分的工程量也巨大。檢查正確性部分,我選擇了對拍。最終,我和另外一位同學一起完成這個評測機和三次作業的測試部分。

​ 總的來說,這單元作業沒有前兩單元的複雜與困難,相對簡單一些,也給了我們充足的時間完成和測試還有摸魚以及寫os。

OO第三單元作業總結

前兩次作業由於功能簡單,我自己並沒有自己設計新的類來凸顯層次化,基本上時按照官方給的介面來設計類實現。但是第三次作業,功能越來越多,不進行層次化設計會導致某個類過於複雜 network 因此第三次作業,我將針對同一類物件的操作和該類物件單獨封裝成一類 box類 而network僅僅充當呼叫方和具體實...

OO第三單元作業總結

本單元作業目的是培養jml的閱讀理解能力,以及按照jml描述規格進行架構設計與實現。要求概述 本次作業下發資料報包括輸入輸出檔案 要求實現的介面檔案和異常類檔案,要求根據介面檔案中的jml描述,實現乙個初步的社交網路模型。設計本單元作業中jml要求已經給出整體設計思路,我們需要考慮細節的實現,以保證...

OO第三單元總結

一 實現規格的設計策略 1.基於規格,設計方法 大部分需要我們寫的方法,都可以根據規格直接寫出來,這些方法一般都是比較簡單的,比如查詢有沒有這個元素 返回某個元素 增加或刪除某個元素。2.根據規格,了解方法功能,自行設計方法 規格怎麼描述,方法怎麼寫也是可行的,但是了解了方法功能,自行設計會更快,比...