2017-2018-20172309 《程式設計與資料結構》第八週學習總結
2017-2018-20172309 《程式設計與資料結構》第八週學習總結
一、教材學習內容總結
相信其它很多同學都是以小頂堆來介紹這一章內容,所以我將以大頂堆來介紹這章內容。
1.1 堆的簡單介紹:
- 堆的定義:(大頂堆)
- 堆實際上是一棵完全二叉樹。
- 堆滿足兩個性質:
- 堆的每一個父節點都大於其子節點;
- 堆的每個左子樹和右子樹也是一個堆。
- 堆的分類:
- 堆分為兩類:
- 最大堆(大頂堆):堆的每個父節點都大於其孩子節點;
- 最小堆(小頂堆):堆的每個父節點都小於其孩子節點;
- 例子:
- 堆分為兩類:
- 堆的操作:
- 堆的定義是二叉樹的拓展,因此他也繼承了二叉樹的所有操作。
- 操作列表(大頂堆為例):
操作 說明 addElement() 將給定元素新增到該堆中去 removeMax() 刪除堆中最大的元素 findMax() 返回一個指向堆中最大元素的引用 - addElement操作:
- addElement方法將給定的Comparable元素新增到堆中的恰當位置,且維持該堆的完全屬性和有序屬性。
- 因為堆是一棵完全二叉樹,因此對於新插入的節點而言,就只有一個正確的位置,要麼是h層左邊的下一個空位置,要麼是h+1層的第一個位置(此時h層已經裝滿了)。
- 如下圖:它有這兩個位置可插入:
- 通常在堆的實現中,我們會對二叉樹的最後一片葉子進行跟蹤記錄。
- 最大堆的插入:
- addElement方法將給定的Comparable元素新增到堆中的恰當位置,且維持該堆的完全屬性和有序屬性。
- removeElement操作:
- 對於大頂堆而言,刪除最大元素即刪除二叉樹的根結點,如果刪除根結點而要想維持堆的完全性,必須與最後一片葉子進行交換位置。
- 交換位置後,必須進行重排序、以維持堆的第二個屬性:排序。
- 用圖表示下過程:
findMax操作
findMax操作將返回一個指向該最大堆中最大元素的引用,也就是根結點的引用。所以實現這一操作只需返回儲存在根結點的元素即可。
1.2使用堆:優先順序佇列。
- 我們先來舉個例子來感受下優先順序佇列。
- 生活中,排隊時講究女士優先。
- 遊戲中,抽獎人民幣玩家獲得好東西的概率更大!
- 好,我們現在來說什麼是優先順序佇列:
- 具有更高優先順序的專案優先,比如女士、人民幣玩家。
- 具有相同優先順序的專案使用先進先出的方法 確定其排序。
- 雖然最大堆根本就不是一個佇列,但是他提供了一個高效的優先順序佇列實現。
關鍵程式碼:
在我看來,這個比較的程式碼是重中之重的。
public int compareTo(PrioritizedObject obj)
{
int result;
if (priority > obj.getPriority())
result = 1;
else if (priority < obj.getPriority())
result = -1;
else if (arrivalOrder > obj.getArrivalOrder())
result = 1;
else
result = -1;
return result;
}
1.3 用連結串列實現堆:
- 因為我們需要再插入元素後能夠向上遍歷樹,因此結點中需要一個指向雙親結點的指標。
public class HeapNode<T> extends BinaryTreeNode<T>
{
public HeapNode<T> parent;//指向雙親的指標。
public HeapNode(T obj)
{
super(obj);
parent = null;
}
}
我們還需要一個能夠跟蹤該堆最後一片葉子 的指標:
public HespNode lastNode;
- 最大堆的各種操作:
- addElement操作:
- addElement操作完成三個任務:
- 再恰當位置新增一個元素。
- 對堆進行重排序。
- 將lastNode指標重新指向新的最末結點。
- addElement操作的時間複雜度為:O(log n)
- addElement操作完成三個任務:
- removeMax操作:
- removeMax主要完成三個操作:
- 將最後一片葉子結點與根結點交換位置。
- 對堆進行重排序。
- 返回初始根元素。
- removeMax操作的時間複雜度為:O(log n)
- removeMax主要完成三個操作:
findMax操作的時間複雜度為O(log n)
1.4用陣列實現堆:
- addElement操作:
- 堆的儲存一般都是用陣列實現的。
- 堆是基於二叉樹實現的,在二叉樹的陣列視線中,對於任一索引值為n的結點,其左結點在2n+1的位置,右結點在2n+2的位置。
用陣列實現堆的操作與用連結串列實現堆的操作步驟一樣。但值得注意的是:連結串列實現和陣列實現的addElement操作時間複雜度雖然都為O(log n),,但實際上鍊表更快點。
1.5 使用堆:堆排序。
排序方法有兩個部分構成:新增列表的每個元素、一次刪除一個元素。
堆排序的時間複雜度為O(log n).
- 進入實戰:還記得上次的一個實驗,給我們一個數組沒讓我們形成一個大頂堆,之後讓我們排序:現在讓我們整理一下思路:
- 首先給出我們一個數組:[45,36,18,53,72,30,48,93,15,35]
- 然後我們應該按照它們的索引形成一個二叉樹:
- 然後重排序,得到一個大頂堆:
- 每輪排序的結果可以這樣表達:
public class test { public static void main(String[] args) { BigArraryHeap<Integer> temp=new BigArraryHeap<Integer>(); int[] list={36,30,18,40,32,45,22,50}; Object[] list2 = new Object[list.length]; //將陣列中的元素新增到大頂堆中 for (int i = 0; i < list.length; i++) temp.addElement(list[i]); System.out.println("大頂堆的輸出結果為:"+ temp); System.out.println(); for(int n = 0; n < list2.length; n++){ list2[n] = temp.removeMax(); String result = ""; for(int a = 0; a <= n; a++){ result += list2[a] + " "; } System.out.println("第" + (n+1) + "次排序:" + temp + " ~ " + result); } System.out.println(); System.out.print("最後排序結果: "); String result = ""; for(int m = 0; m < list.length; m++){ result += list2[m] + " "; } System.out.println(result); } }
- 執行結果為:
二、教材學習中的問題和解決過程
問題1:如何理解這段話,該怎樣實現?
通常在堆的實現中,我們會對二叉樹的最後一片葉子進行跟蹤記錄。
問題1解決方案:
就是在對堆進行刪除操作的時候需要將根結點與最後一片葉子結點進行交換位置,所以每一次操作都得更新lastNode結點。
- 問題2:書上介紹了用陣列實現的堆排序,那麼連結串列實現的堆排序應該怎樣排序?
問題2解決方案:書上陣列對對進行排序是寫了一個方法,當想要進行排序的時候直接呼叫這個方法就OK,而我們選在在測試類裡面直接進行排序,使用最大堆,取出最大堆輸出,然後就可以直接輸出。
如圖:
問題三:在網上搜尋有關於書上的資料室,出現了這麼一個尷尬場面:
之後我點進去看了一下:
原來是講解了有關:棧記憶體和堆記憶體。
講了這麼個些東西,來潦草的總結下:
- ava把記憶體劃分成兩種:一種是棧記憶體,一種是堆記憶體
在函式中定義的一些基本型別的變數和物件的引用變數都在函式的棧記憶體中分配。 - 當在一段程式碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。 - 堆記憶體用來存放由new建立的物件和陣列。
- 在堆中分配的記憶體,由Java虛擬機器的自動垃圾回收器來管理。
- 在堆中產生了一個數組或物件後,還可以在棧中定義一個特殊的變數,讓棧中這個變數的取值等於陣列或物件在堆記憶體中的首地址,棧中的這個變數就成了陣列或物件的引用變數。
- 引用變數就相當於是為陣列或物件起的一個名稱,以後就可以在程式中使用棧中的引用變數來訪問堆中的陣列或物件。
(大概就看懂了這麼多)
程式碼除錯中的問題和解決過程
- 問題1:如何用堆構建一個佇列、棧?
問題1解決方案:
首先我們得知道我們必須運用優先順序堆,並且每一次新增元素,優先順序都加一(從0開始)。
- 然後我們根據佇列、棧的特點來輸出
- 佇列是一種先進先出的結構,所以我們只要使用最小堆中的removeMin方法即可輸出最先進去的元素。
- 棧是一種先進後出的結構,所以我們只要使用最大堆中的removeMax方法即可輸出最後面進去的元素,因為它的優先順序高,所以他在前面輸出。
- 結果
- 問題二:符合把一個Object型資料轉化為char型別資料?
- 原問題是這樣的我需要把
Object operator= +
轉化為char
型資料,但是如果直接轉,比如這樣(char)operator
是會丟擲CalssCastException
錯誤的! - 之後解決辦法是先轉化成String 然後再轉化成char型別。
//像這樣:
String a = String.valueOf(ope.pop());//ope.pop()出來的是一個Object型資料。
operator = a.charAt(0);
程式碼之家
- 小頂堆:
- 大頂堆:
- pp專案程式碼地址:
上週考試錯題總結
第十章錯題
錯題1及原因:
What type does "compareTo" return? A .int B .String C .boolean D .char
錯誤原因:comparaTo方法返回的是 -1,0,1
而return "a".comparaTo("b")>0
為false
orture
第十一章錯題
無
第十二章錯題
Since a heap is a binary search tree, there is only one correct location for the insertion of a new node, and that is either the next open position from the left at level h or the first position on the left at level h+1 if level h is full. A .True B .Flase
錯誤原因:堆是一棵完全二叉樹、不是一顆二叉搜尋樹。自己瞎了眼!!!!
點評模板:
部落格或程式碼中值得學習的或問題:
- 內容很詳細,把堆介紹的很透徹,
- 運用豐富的圖片表達思想、比如插入、刪除結點的介紹。
提出問題有點少。
點評過的同學部落格和程式碼
- 本週結對學習情況
- 20172310
- 結對學習內容
- 第十二章內容:堆、優先順序佇列
- 實驗二:樹的綜合運用
...
其他(感悟、思考等,可選)
這一章比起前面相對比較簡單,但自己不能鬆懈.哎,比較難受的是這兩天的假期都要貢獻給部落格了~~~~~o(╥﹏╥)o
學習進度條(上學期截止7200)
程式碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 260/0 | 1/1 | 05/05 | |
第二週 | 300/560 | 1/2 | 13/18 | |
第三週 | 212/772 | 1/4 | 21/39 | |
第四周 | 330/1112 | 2/7 | 21/60 | |
第五週 | 1321/2433 | 1/8 | 30/90 | |
第六週 | 1024/3457 | 1/9 | 20/110 | |
第七週 | 1024/3457 | 1/9 | 20/130 | |
第八週 | 643/4100 | 2/11 | 30/170 |
參考資料
1.優先佇列
2.堆排序
3.java 各種資料型別之間的轉化
4.java中的棧與堆