20172323 2018-2019-1 《程式設計與資料結構》第八週學習總結
20172323 2018-2019-1 《程式設計與資料結構》第八週學習總結
教材學習內容總結
本週學習了第12章優先佇列與堆
- 12.1 堆
- 堆是具有兩個附加屬性的一棵二叉樹,它是一棵完全樹,對於每一結點,它小於或等於其左孩子和右孩子,這樣定義下的堆是最小堆,如果對於每一結點,它大於或等於其左孩子和右孩子,那麼它就是最大堆。
- 最小堆將其最小元素儲存在該二叉樹的根處,且其根的兩個孩子同樣也是最小堆。
操作 說明 addElement 將給定元素新增到該堆中 removeMin 刪除堆的最小元素 findMin 返回一個指向堆中最小元素的引用
如圖是一個最小堆
addElement方法將給定的Comparable元素新增到堆中的恰當位置處,且維持該堆的完全性屬性和有序性屬性
如果一棵二叉樹是平衡的,及所有葉子都位於h或者h-1層,其中h為log2n,n是樹中的元素數目,以及所有h層中的葉子都位於該樹的左邊,那麼該樹就被認為是完全的。因為堆是一棵完全樹,所以對於新插入的結點只存在一個正確的位置,要麼是h層左邊的下一個空位置,要麼就是h+1層左邊的第一個位置(如果h層是滿的話)
- 新結點新增之後,將考慮堆的排序性。,該結點將於它的雙親結點進行比較,如果新結點小則要與雙親結點進行互換,之後再沿樹往上進行比較直至新值大於雙親或者位於根結點。
- 在堆實現中,我們會對樹中的最末一個結點(最末一片葉子)進行跟蹤記錄。
2新增到堆之後,將於其雙親進行比較上浮直至堆滿足其順序屬性 removeMin操作將刪除最小堆中的最小元素並返回他,最小堆中的元素即是它的根結點,為了保持樹的合法性,需要有一個能替換根的合法元素,且它是樹中最末一片葉子上的元素。將最末一片葉子移至根處之後,又需要將該堆進行重新排序。排序方法需要將該結點與最小孩子進行比較然後逐漸下沉到合適的位置。借用上圖,如果將根結點1刪去,那麼最末葉子6就將成為新的根結點,它將與2、5進行比較最終落在5現在的位置,而2將成為新的根結點。
- 12.2 使用堆:優先順序佇列
- 優先順序佇列就是遵循兩個排序規則的集合。一是具有更高優先順序的專案在先,二是具有相同優先順序的專案使用先進先出方法確定其排序。
- 雖然最小堆根本就不是一個佇列,但是他卻提供了一個高效的優先順序佇列實現
- 12.3 用連結串列實現堆
- 堆中結點必須儲存指向其雙親的指標。
- 連結串列實現addElement操作的時間複雜度為O(logn)
- removeMin操作的時間複雜度同樣為O(logn)。
- findMin操作時間複雜度為O(1)
- 12.4 用陣列實現堆
- 堆的陣列實現比連結串列實現更為簡潔。
- 在二叉樹的陣列實現中,樹的根位於位置0處,對於每一結點n,n的左孩子將位於陣列的2n+1
處,n的右孩子將位於陣列的2(n+1)位置處 - 陣列實現不需要確定新結點雙親,時間複雜度與連結串列實現相同,但陣列實現效率更高
- 連結串列實現與陣列實現的removeMin操作的複雜度同為O(logn)
- 12.5 使用堆:堆排序
- 堆排序的由兩步構成:新增列表的每個元素,然後一次刪除一個元素
- 堆排序的複雜度為O(nlogn)
教材學習中的問題和解決過程
問題1:連結串列實現堆的過程中的addElement操作第一步要確定要插入結點的雙親,為什麼在最壞的情況下要從堆的右下結點遍歷到根結點之後還要再從根結點遍歷到堆的左下結點?
問題1解決方案:這個問題我思考了小半個小時,新增的第一步需要確定插入結點的雙親,因為需要比較雙親結點的值與新結點的值,決定新結點是否要上浮。所以最壞的情況應該是新結點一直上浮到根結點,此時按最小堆的定義來看,新增元素這一操作應該是停止了,因為堆頂是最小元素了,它的左孩子和右孩子的值都應該比它要小,所以不需要繼續遍歷它的左孩子直到左下結點了吧。和同學討論之後,才發現我的理解錯在哪裡了。它這裡指的是遍歷的最壞情況需要從右下結點一直到根再到左下結點,而不是結點互相之間的比較需要讓結點上浮之後再次下沉(事實上跟我分析的一樣,他也無法做到)。它這裡指的是查詢確定新結點的雙親結點的最壞情況
如上醜圖,新增元素時剛好遇見滿樹的情況,需要從右下最後一片葉子開始找起,一直到左下結點,才最終確定要插入的元素的雙親結點。
- 問題2:對書上程式碼
getNextParentAdd
方法的理解 - 問題2解決方案:
HeapNode<T> result = lastNode;
while ((result != root) && (result.getParent().getLeft() != result))
result = result.getParent();
if (result != root)
if (result.getParent().getRight() == null)
result = result.getParent();
else {
result = (HeapNode<T>) result.getParent().getRight();
while (result.getLeft() != null)
result = (HeapNode<T>) result.getLeft();
}
else
while (result.getLeft() != null)
result = (HeapNode<T>) result.getLeft();
return result;
首先教材講到,這是一個返回指向插入結點的雙親結點的引用。所以就容易理解到,這個方法就是確定新插入結點的雙親結點。也就通過此來決定新新增元素的位置。
一開始,新設一個變數result指向lastNode,即指向最後一片葉子的引用。
接下來通過判斷最後一片葉子的情況來確定插入結點的雙親結點,當最後一片葉子不是根結點且同時不是左孩子的時候,就將result的父結點付給result,直到不滿足兩個條件之一跳出迴圈。當最後一片葉子是根結點時,已經確定了新結點的雙親結點,可以進入下一步,而如果最後一片葉子是右結點,就說明當前父結點是滿的,不能再在當前父結點下新增新元素,所以將result指向result的父親,方便尋找一個沒有滿的父結點。下一步,此時result跳出while迴圈,要麼它是根結點,要麼它是左孩子。如果它是左孩子,即進入if語句內,判斷它的兄弟結點是否為null,如果返回true,那麼新新增元素的雙親結點就確定了是result的父結點,而新結點將作為result的右孩子新增到堆中,如果返回false,result將指向這個右孩子,並找到它的最左下的位置新增。如果result是指向根結點的,那麼也一直迴圈到它的最左下位置,新增新元素。
這個問題的解決參考了於欣月同學的部落格,她在解釋時運用了圖文結合的形式,對我理解該問題起了很大幫助
程式碼除錯中的問題和解決過程
問題1:測試LinkedHeap類,實現層序輸出、前序中序後序各種輸出,很不巧的是它出現了亂碼的情況
問題1解決方案:這個問題的出現充分說明我還沒能掌握迭代器的精髓,首先方法的使用就是完全錯誤的,我還把它當作簡單的toString方法在加以使用。所以自然輸出不來需要的結果,標準的應該是如圖,先設定一個迭代器的物件,通過for迴圈一個一個呼叫迭代器裡的內容,如圖
程式碼託管
上週考試錯題總結
- In removing an element from a binary search tree, another node must be ___________ to replace the node being removed.
A .duplicated
B .demoted
C .promoted
D .None of the above
- 解析:從二叉查詢樹中刪除一個元素時,必須推選出另一個結點來代替要被刪除的那個結點
。demoted意思是降級的,promoted是升級的,從概念來看,替代元素應該是該結點的中序後繼者,所以該是c。
- The Java Collections API provides two implementations of balanced binary search trees, TreeSet and TreeMap, both of which use a ___________tree implementation.
A .AVL
B .red/black
C .binary search
D .None of the above
- 這好像是13章的內容亂入了吧,TreeSet和TreeMap類使用的是紅黑平衡二叉查詢樹
- The best comparison sort in terms of order is:
A .O(1)
B .O(n)
C .O(log(n))
D .O(nlog(n))
- Linear search has logarithmic complexity, making it very efficient for a large search pool.
A .true
B .false
- 線性查詢具有線性時間複雜度O(n)。
- Bubble, Selection and Insertion sort all have time complexity of O(n).
A .true
B .false
排序方法 時間複雜度 選擇排序 O(n^2) 插入排序 O(n^2) 氣泡排序 O(n^2)
- Insertion sort is an algorithm that sorts a list of values by repetitively putting a particular value into its final, sorted, position.
A .true
B .false - 插入排序通過反覆地將某一特定值插入到該列表的某個已排序的子集中來完成對列表值的排序。每一個值只需要插入一次,而不是重複地插入。
結對及互評
- 部落格中值得學習的或問題:
基於評分標準,我給譚鑫的部落格打分:8分。得分情況如下:
正確使用Markdown語法(加1分)
模板中的要素齊全(加1分)
教材學習中的問題和解決過程, 三個問題加3分
程式碼除錯中的問題和解決過程, 三個問題加3分基於評分標準,我給方藝雯的部落格打分:8分。得分情況如下
正確使用Markdown語法(加1分):
模板中的要素齊全(加1分)
教材學習中的問題和解決過程, 兩個問題加2分
程式碼除錯中的問題和解決過程, 四個問題加4分- 本週結對學習情況
- 上週部落格互評情況
其他
這周的教材學習比較容易,所以花的時間相對較少,但是實驗令人難受。
學習進度條
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 8/8 | |
第二週 | 470/470 | 1/2 | 12/20 | |
第三週 | 685/1155 | 2/4 | 10/30 | |
第四周 | 2499/3654 | 2/6 | 12/42 | |
第六週 | 1218/4872 | 2/8 | 10/52 | |
第七週 | 590/5462 | 1/9 | 12/64 | |
第八週 | 993/6455 | 1/10 | 12/76 | |
第九周 | 1192/7467 | 2/12 | 10/86 |