學號 20172326 《程式設計與資料結構》第八週學習總結
學號 20172326 《程式設計與資料結構》第八週學習總結
教材學習內容總結
堆
- 最小堆 是一棵完全樹。對每一結點,它小於或等於其左孩子和右孩子。同理,也存在最大堆,其結點大於或等於他的左右孩子。
- 所具有的的方法(其繼承了BinaryTree的方法)
addElement
removeMin
findMin
- addElement 插入操作。如果不進行比較,插入元素可能會導致堆不符合規則。在保證其始終為完全樹的基礎上,根據最小堆或者最大堆進行填充。同時,根據其最大堆或最小堆的性質,插入時需要與其父結點以及孩子結點進行比較,例如,對於一個最小堆,如果發現有孩子結點小於待插入結點或其小於其父結點,此時就需要進行調換位置。
- 因此,對最後一個結點進行記錄,來確定新插入結點的位置以及其他資訊。
- 插入元素的幾種情況。由於記錄了最後一個結點,因此我們每次預設從最後一個結點開始1.最後一個結點時右子樹的右結點。此時,最小堆為滿樹,直接將帶插入結點插入左子樹最左結點即可。2.最後結點為右子樹的左結點,此時,將帶插入結點插入其兄弟位置,即右子樹的右孩子位置。3.位於左子樹的左孩子,直接將其插入其兄弟位置即可。4.最後結點為左子樹的右結點。那麼將帶插入結點插入至最後結點的父結點的兄弟結點的左孩子位置即可。這個情況是最複雜的。
- removeMin操作。因為根據定義,堆的根要麼是最大的,要麼是最小的。因此,尤其是最小堆。這個操作就相當於刪除根。刪除的同時需要找到堆中其他元素來進行替換,且這個元素時唯一的,也就是樹中的最末一片葉子上的元素。
- findMin很簡單,就不在此贅述
調整重排序,當建立起一個二叉樹後,如果需要將其轉化為一個最小堆,那麼就要經過數個步驟。
1.調整過程中,總是將根結點(被調整結點)與左右孩子比較;
2.不滿足堆條件時,將根結點與左右孩子中較大者交換;
3.這個調整過程一直進行到所有子樹都是堆或者交換到葉子為止。從哪個結點開始呢?根據經驗,從第n/2個元素開始,若n為奇數,擇不保留小數。依次遞減。例如,n為8,則從第四個開始,然後從第三個,第二個依次與子結點比較。每經過一次比較,都能找出現有樹的一個最小值。順帶一提,在資料空間中同樣也有堆疊一說,但與我們現在所學的資料結構的堆和棧有很大區別
教材學習中的問題和解決過程
- 問題1:最小堆的刪除問題
- 問題1理解:書上的內容一開始就迷惑了我一下,
當然我也看的不是很仔細刪除時,直接將根移除,之後把最後結點放到根處就行。這就結束了?如何保證最後結點就是最小的呢?帶著疑惑,繼續往下看,同時,結合程式碼,我逐漸理清了思路。移除根是removeMin的直接目的,所以我們要刪除根。但把根刪了不能拍屁股走人,總有結點要補上去。為了維護這個最小堆,至少要保證其是一個完全樹,因此,我們就把最後結點拿出來,放到根的位置。因為最後結點的移除是不會改變其完全樹的性質。完成這一步後,在保證了其樹的基礎上,再對其進行重新排序。與插入結點的情況類似,當最後結點為右子樹的右結點時,直接放至根處即可。當最後結點為右子樹的左結點時,同樣,直接放至根處即可。當最後結點為左子樹的左結點時,直接放至根結點就行。 - 問題2:最小堆怎樣提供了一個高效的優先順序佇列實現?
問題2理解:首先明確何為優先順序佇列。第一,具有更高優先順序的專案在先。第二具有相同優先順序專案使用先進先出方法來確定其排序。顯然堆不是一個佇列。而且,他甚至不是線性結構,但正因為其非線性結構,使得在各方面都有方便之處。例如,一個普通的佇列,只能在兩端進行插入刪除操作。但是作為非線性資料結構的堆(樹)便不受這種限制。根據優先度可隨意插入刪除元素,且有著高效的查詢效率。因此,從多個角度來說,其都是一種高效的優先順序佇列實現。
程式碼除錯中的問題和解決過程
- 問題:pp12.1的實現問題
問題解決方案:用堆實現佇列。佇列需要先進先出,用堆怎樣實現?和別的同學交流一波並結合自己的理解,我有了這幾種思路。第一種,利用書上的優先順序佇列進行實現。例如,我先輸入五個數,則第一個輸入的數的優先順序為5,依次類推。也就是說,利用優先順序來代表那個最先出來。因為不存在同時兩個數進入陣列,所以也就不會出現優先順序相同的情況。
public void addElement(T object, int priority)
{
PrioritizedObject<T> obj = new PrioritizedObject<T>(object, priority);
super.addElement(obj);
}
public T removeNext()
{
PrioritizedObject<T> obj = (PrioritizedObject<T>)super.removeMin();
return obj.getElement();
}
測試類是這樣的
PriorityQueue pq= new PriorityQueue();
pq.addElement("a",1);
pq.addElement("b",2);
pq.addElement("c",3);
pq.addElement("o",4);
pq.addElement("g",5);
pq.addElement("cyka bylat",6);
System.out.println(pq.removeNext());
pq.addElement("edd mounted",5);
System.out.println(pq.removeNext());
執行結果是這樣的
第二種思路呢,就是以已有的LinkedHeap為基礎,加上一個變數,這個變數的意義就是確定先後順序,畢竟,堆不能被限制只能在兩端操作,那麼我們就以其先後順序為其結點的比較值。詳細地說,我輸入一組數“55,23,78,66,12”那麼第一個輸入的數55的order為1,依次類推。同時,不能忘記的是,我們恰恰是使用小頂堆實現的,所以移除元素時,將小order的先出。將removeMin略加改造就行了。
public void addElement(T obj)
{
HeapNode<T> node = new HeapNode<T>(obj);
node.setOrder(count);
count++;
if (root == null)
root=node;
else
{
HeapNode<T> nextParent = getNextParentAdd();
if (nextParent.getLeft() == null)
nextParent.setLeft(node);
else
nextParent.setRight(node);
node.setParent(nextParent);
}
lastNode = node;
modCount++;
if (size() > 1)
heapifyAdd();
}
這裡就是關鍵程式碼,刪除部分基本沒什麼變化。就不贅述了
程式碼託管
上週考試錯題總結
- 錯題1及原因,理解情況
- After one pass on the numbers ( 5 3 9 5 ), what would be the result if you were to use Bubble Sort?
- 一次排序,將大的排至最後所以就有5395->3595->3559
- 錯題2及原因,理解情況
- Insertion sort is an algorithm that sorts a list of values by repetitively putting a particular value into its final, sorted, position.
- 插入排序就是每次將最小的元素排至最前,對已經排好的元素,不存在重複排序。
- 錯題3及原因,理解情況
- One of the uses of trees is to provide simpler implementations of other collections.
這道題我真的不懂,待我問問
其他(感悟、思考等,可選)
堆的學習還行,主要是利用了樹的性質,然後有了一些有趣的性質
學習進度條
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 3/3 | |
第二週 | 409/409 | 1/2 | 5/8 | |
第三週 | 1174/1583 | 1/3 | 10/18 | |
第四周 | 1843/3426 | 2/5 | 10/28 | |
第五週 | 539/3965 | 2/7 | 20/48 | |
第六週 | 965/4936 | 1/8 | 20/68 | |
第七週 | 766/5702 | 1/9 | 20/88 | |
第八週 | 1562/7264 | 2/11 | 20/108 |
結對及互評
- 部落格中值得學習的或問題:
排版精美,對於問題研究得很細緻,解答也很周全。 - 程式碼中值得學習的或問題:
程式碼寫的很規範,思路很清晰,繼續加油!