(最大堆)對於每個結點,它大於或等於其左孩子和右孩子。html
最大堆將其最大元素存儲在二叉樹的根處,其根的兩個孩子一樣也是最大堆。java
考慮排序屬性,將該新值和雙親值進行比較,若是新結點小於雙親則互換位置,沿着樹向上繼續此過程,直至該新結點要麼是大於雙親要麼是位於堆的根處。node
添加元素0:
![]()
![]()
git
新根元素與較小的子結點進行比較,若是子結點更小就替換,沿着樹向下這一過程,直至該元素要麼位於某片葉子要麼比兩個子結點都小。算法
findMin方法將返回一個指向最小堆中的最小元素的引用,只需經過返回存儲在根處的元素。api
三種方法的時間複雜度:數組
堆--優先級隊列(遵循兩個排序規則的集合,具備更高級的項目在先,具備相同優先級的項目使用先進先出的方法來肯定其排序)數據結構
addElement操做使用了兩個私有方法getNextParentAdd和heapifyAdd兩個方法,getNextParentAdd方法是返回一個指向某結點的引用,該結點爲插入結點的雙親。heapifyAdd方法是完成堆的任何重排序,從那片新葉子開始,向上處理至根處。ide
- 在恰當位置處添加一個新元素,對堆進行重排序來維持排序屬性,將lastNode指針從新設定爲指定新的最末結點。
removeMin操做使用了兩個私有方法getNewLastNode和heapifyRemove兩個方法,getNewLastNode方法返回一個指向某一結點的引用,該結點將是新的最末結點。heapifyRemove方法將完成任何有必要的樹重排序,從根向下進行。性能
- 用存儲在最末結點處的元素替換存儲在根處的元素,對堆進行重排序,以及返回初始的根元素。
findMin方法返回一個指向存儲在根結點的元素的內容。
addElement操做使用了私有方法heapifyAdd方法,用於在必要時對該堆進行重組。
- 在恰當位置處添加新結點,對堆進行重排序來維持排序屬性,將count遞增。
removeMin操做使用了私有方法heapifyRemove方法,用於在必要時對該堆進行重組。
- 用存儲在最末結點處的元素替換存儲在根處的元素,對堆進行重排序,以及返回初始的根元素。
findMin方法返回一個指向存儲在根結點的元素的內容。
堆排序
問題1解決方案:先說後面的問題,最小堆和最大堆是二叉堆的兩種表現形式,最大堆是除了根之外的全部結都要知足:父結點大於子結點;而最小堆偏偏相反,最小堆是除了根之外的全部結都要知足:父結點小於子結點。因此,二叉堆能夠根據優先級肯定出隊列的前後順序。
- d堆是徹底d叉樹,就是每個結點有d個子結點,同時還要知足每一個結點從左到右的順序。
- 左式堆是具備堆序性質的二叉樹,左式堆的任意結點的值比其子樹的任意結點值均小,但和通常的二叉堆不一樣,左式堆再也不是一棵徹底二叉樹。
- 斜堆也叫自適應堆,是一種使用二叉樹實現的堆狀數據結構,使用的是二叉樹而不是徹底二叉樹,因此在總體來看,斜堆會是極不平衡的一個堆,但其合併的速度遠遠大於二叉堆。
- 二項堆是是二項樹的集合或是由一組二項樹組成,在O(logn)的時間內便可完成兩個二項堆合併操做,因此二項堆是可合併堆,基於二項堆實現的優先隊列和進程調度算法有着很好的時間性能。
問題1的解決方案:刪除一個元素以後,進行總體的輸出會出現被刪除元素,經過對代碼的分析,在刪除最小結點後將末葉結點放到根處以後,沒有將葉結點內容進行刪除,而是在計數變量和操做次數進行遞減,這樣的話葉結點和暫時的根結點樹都會有同一元素。因此在tree[0]=tree[count - 1];
和heapifyRemove()
之間添加一句tree[count - 1] = null;
直接令其爲空。針對刪除時對堆的排序方法(向下遍歷),先判斷根結點的左側和右側是否爲空,若是爲空的話就直接跳過循環讓新的根結點爲根結點,若是不爲空的話會有兩種狀況,只有一個子結點,此時右側爲空,則左側不爲空,記錄此時左結點的索引值,若是左右都不爲空的話進行判斷左側和右側誰更小(最小堆)。進入循環,循環條件是索引值小於總共數量和索引值位置與新根結點的比較,node始終是next的父結點的索引值,不斷向下遍歷,而對於每個結點他的索引值是n的話,其左子結點爲2n+1,右子結點爲2(n+1),和以前操做相似,判斷來年兩個子結點的大小,向下不斷遍歷,next的值賦給node,並找node的孩子的索引,令next從新指向node的孩子直至不知足next索引值超過總的或是元素大小不符合的時候會跳出循環,node的位置就是替代新結點的位置。針對添加時對堆的排序方法(向上排序),添加的方法進行的排序比較簡單,直接肯定添加的位置是否比父結點小,若是小的話,進行調換;大得話跳出循環結束排序。和以前的相似,子結點的索引值爲count-1的話,那麼其父結點位置爲next-1/2,不斷的和父結點進行比較直至向上遍歷結束,當跳出循環後,此時的next位置就是新添結點的位置。
未加
tree[count - 1] = null
:
添加以後:
問題2的解決方案:用堆來實現隊列的問題,由於隊列是一個線性結構,先進先出,而堆是徹底二叉樹。因此,須要根據把每個進行隊列的元素標上號,按照號碼牌的內容來實現堆的形式,可是若是這樣的話,咱們就不能直接往堆裏面插入泛型元素,須要定義個類,而在這個類的內部須要每定義一個就會自增數量,好比先進的是A元素,就爲1;再進的是B元素,就爲2...以此類推。相似的形式在實驗室內就幫助學長實現過,因此定義類個類並不難。可是,須要注意的是要在類中寫出比較方法,肯定比較元素是誰。可是,我第一次實現的過程當中,將這個計數的比較放在外部進行,這樣實現的話能夠肯定誰先進對誰先出隊。可是在實現輸出隊列內容的時候,會發現輸出的內容不是進隊的形式。而是中序的形式(問題3會解決此問題)。可是,我發現隊列的輸出形式能夠每次刪除堆的根結點,用一個暫時變量存放內容,這樣的話就復刻了一份堆,利用了復刻的堆實現輸出而保持了原堆的內容。可是在實現這種狀況會始終出現兩個堆被刪的一乾二淨,雖然會按照隊列的形式進行輸出,可是日後刪除就會有問題。通過改寫,嘗試把刪除元素存放到暫時變量中,在給它塞回去。這種方法雖然實現了不報錯,可是始終會輸出第一個元素,其餘元素不輸出。我認爲是由於我規定的存放數字是第一個就永遠第一個。經過侯澤洋同窗的交流,發現個人代碼都是複製粘貼,沒用到繼承,若是用繼承的話就直接調用父類的方法就能夠了,並且規定的標記數字也能夠寫進方法裏面,不用本身規定,保持了隊列的完整性。可是,這樣的話我仍是隻輸出第一個元素。後來感受如歸的位置從新定義一下,就運行成功了,可能和第一次犯錯同樣就是在再次入隊的時候他的標記數字還是以前的就會一直輸出,從新定義一下就會將以前的標記數字抹去換新。
進行復刻致使兩個堆的元素都被刪除:
實現隊列輸出(只是第一個元素的輸出):
真正實現隊列輸出:
問題3的解決方案:這個問題是在課堂測試上發現的,可是我在ArrayHeap方法裏面並無找到toString方法,可是調用toString沒有問題。後來經過單步調試跳到了ArrayBinary的toString。經過繼承會調用父類的方法,如過在子類中重寫方法會調用子類的方法。鏈表實現的堆也是如此。因此,針對toString方法咱們能夠有兩種修改方法,一是修改子類重寫,二是修改父類直接調用父類的。
本週結對學習狀況
20172314方藝雯
20172323王禹涵
結對學習內容:堆和優先級隊列
第十二章的優先隊列與堆的內容並非很難,和第十一章相似,都是在樹的基礎上添加附加條件,因此並非很難,並且有不少示例代碼能夠學習,這樣的話更減小困難。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 15/15 | |
第二週 | 703/703 | 1/2 | 20/35 | |
第三週 | 762/1465 | 1/3 | 20/55 | |
第四周 | 2073/3538 | 1/4 | 40/95 | |
第五週 | 981/4519 | 2/6 | 40/135 | |
第六週 | 1088/5607 | 2/8 | 50/185 | |
第七週 | 1203/6810 | 1/9 | 50/235 | |
第八週 | 2264/9074 | 2/11 | 50/285 |