「堆」排序從**中可以看出,整個排序過程分為兩個迴圈,第乙個迴圈要完成的就是將現在的待排序序列構建成乙個大頂堆。第二個迴圈要完成的就是逐步將每個最大值的根節點與末尾元素交換,並再調整其成為乙個大頂堆。很明顯,我們可以發現它們都是
二叉樹,如果觀察仔細些,還能看出它們都是
完全二叉樹。上圖中根節點是所有元素中最大的,右圖的根節點是所有元素中最小的。再仔細看看,發現左圖每個節點都比它的左右孩子要大,右圖每個節點都比它的左右孩子要小。這就是我們要講的堆結構。
堆是具有下列性質的完全二叉樹:每個節點的值都大於或等於其左右孩子節點的值,稱為大頂堆;或者每個節點的值都小於或等於其左右孩子結點的值稱為小頂堆。這裡我們需要注意從堆的定義可知,根節點一定是堆中所有節點最大(小)者。較大(小)的結點靠近根節點(但也不絕對,比如右圖小頂堆中60、40均小於70,但它們並沒有70靠近根節點)。按照層序遍歷的方式給結點從1開始編號,則結點之間滿足如下關係:
上圖的解釋如下完全二叉樹的性質:
i 編號的結點是非葉子結點, 如果i=1 (編號從1開始) , 則結點i是二叉樹的根,無雙親;如果i>1,則其雙親是結點[i/2]。那麼對於有n個結點的二叉樹而言,它的i值自然就是小於等於[n/2]了。堆排序演算法堆排序(heap sort)就是利用堆(假設利用大堆頂)進行排序的方法。它的基本思想是,將待排序的序列構成乙個大頂堆。此時,整個序列的最大值就是堆頂的根節點。將它移走(其實就是將其與堆陣列的末尾元素交換,此時末尾元素就是最大值),然後將剩餘的n-1個序列重新構造成乙個堆,這樣就會得到n個元素中的次小值。如此反覆執行,便能得到乙個有序序列了。例如下圖所示,圖①是乙個大堆頂,90為最大值,將90與20(末尾元素)互換,如圖②所示,此時90就成了整個堆序列的最後乙個元素,將20經過調整,使得除90以外的結點都繼續滿足大頂堆定義(所有結點都大於等於其子孩子),見圖③,然後再考慮將30與80互換......如何由乙個無序序列構建成乙個堆?堆排序**:如果再輸出堆頂元素後,調整剩餘元素為乙個新的堆?
- (void)heapsort:(nsmutablearray *)list
while(size > 0)
nslog(@"%@",list);
}- (void)createbiggesheap:(nsmutablearray *)list withsize:(nsinteger) size beindex:(nsinteger)element
else
lchild = element * 2 +1;
rchild = lchild + 1; //重新計算子樹位置
}//只有左子樹且子樹大於自己
if (lchild < size && list[lchild] > list[element])
}
假設我們要排序的序列是(50,10,90,30,70,40,80,60,20)。共9個,那麼第一次調整底的位置是從9/2 = 4開始,4->3->2->1的變數變化,為什麼不是從1到9或者9到1,而是從4到1呢,看下圖就明白了,它們有什麼規律?它們都是有孩子的結點。注意灰色結點的下表編號就是1、2、3、4.
我們所謂的將待排序的序列構建成為乙個大頂堆坑,其實就是從下往上、從右到左,將每個非終端節點(非葉結點)當作根節點,將其和其子樹調整為大頂堆,i的4->3->2->1的變數變化,其實也就是30、90、10、50的結點調整過程。調整方式便是與自己的左右子樹的對比,大的交換位置到堆頂,按次序最終取得最大值。示例圖如下:
動效圖如下:
解釋:
1、 從下往上,從右往左的順序查詢每個非葉子結點,對比子結點,與最大結點交換位置,交換的新位置再與其子結點比較、移動,遍歷後最終找到最大值。堆排序複雜度分析:2、把堆頂和最後的元素交換位置,排除最後的位置,重複1步驟,找到遍歷後的最大值,放到倒數第二的位置,依次直到結束。
堆排序執行時間主要是消耗在初始構建堆和在重建堆時的反覆篩選上。在構建堆的過程中,對每個終端節點最多進行兩次比較操作,因此整個排序堆的時間複雜度為o(n)。
在正式排序時,第i次取堆頂記錄重建堆需要用o(logi)的時間,並需要取n-1次堆頂記錄,因此總體來說,堆排序的時間複雜度為o(nlogn)。由於堆排序對原始資料的排序狀態並不敏感,因此它無論是最好、最壞和平均時間複雜度均為o(nlogn)。在這效能上顯然要遠遠好過於冒泡、選擇、插入的o(n²)的時間複雜度了。
空間複雜度上,它只有乙個用來交換的暫存單元,也是非常不錯。不過由於記錄的比較和交換是跳躍式進行,因此堆排序也是一種不穩定的排序方法。
另外,由於初始構建堆排序需要的比較次數較多,因此,它不適合待排序序列個數較少的情況。
演算法總結 堆排序
在軟體設計相關領域,堆 heap 的概念主要涉及到兩個方面 堆排序的時間複雜度是o nlgn 與快速排序達到相同的時間複雜度.但是在實際應用中,我們往往採用快速排序而不是堆排序.這是因為快速排序的乙個好的實現,往往比堆排序具有更好的表現.堆排序的主要用途,是在形成和處理優先順序佇列方面.另外,如果計...
堆排序演算法 總結
最近面試,老是被問到堆排序演算法。回答時老是感覺思路不清楚,現在總結一下,把思路弄清楚的。1.堆排序是利用堆的特性對記錄序列進行排序的一種排序方法。好的那麼堆得特性是什麼呢?堆得定義 堆是滿足下列性質的數列 如下圖最開始是乙個小頂堆。當把97和13 交換後不是堆了,所以我們要調整根節點使之成為堆即篩...
堆排序演算法 總結
最近面試,老是被問到堆排序演算法。回答時老是感覺思路不清楚,現在總結一下,把思路弄清楚的。1.堆排序是利用堆的特性對記錄序列進行排序的一種排序方法。好的那麼堆得特性是什麼呢?堆得定義 堆是滿足下列性質的數列 如下圖最開始是乙個小頂堆。當把97和13 交換後不是堆了,所以我們要調整根節點使之成為堆即篩...