毫無疑問,排序兩個字沒必要去死磕,這裡的重點,在於排序的方式,堆排序,就是以堆的形式去排序,毫無疑問,了解堆很重要。
那麼,什麼是堆呢?
這裡,必須引入乙個完全二叉樹的概念,然後過渡到堆的概念。
上圖,就是乙個完全二叉樹,其特點在於:
從作為第一層的根開始,除了最後一層之外,第n層的元素個數都必須是2的n次方;第一層2個元素,第二層4個,第三層8個,以此類推。
而最後一行的元素,都要緊貼在左邊,換句話說,每一行的元素都從最左邊開始安放,兩個元素之間不能有空閒,具備了這兩個特點的樹,就是一棵完全二叉樹。
那麼,完全二叉樹與堆有什麼關係呢?
我們假設有一棵完全二叉樹,在滿足作為完全二叉樹的基礎上,對於任意乙個擁有父節點的子節點,其數值均不小於父節點的值;這樣層層遞推,就是根節點的值最小,這樣的樹,稱為小根堆。
同理,又有一棵完全二叉樹,對於任意乙個子節點來說,均不大於其父節點的值,如此遞推,就是根節點的值是最大的,這樣的數,稱為大根堆。
如上圖,左邊就是大根堆;右邊則是小根堆,這裡必須要注意一點,只要求子節點與父節點的關係,兩個節點的大小關係與其左右位置沒有任何關係。
明確下大根堆,小根堆的概念,繼續說堆排序。
現在對於堆排序來說,我們先要做的是,把待排序的一堆無序的數,整理成乙個大根堆,或者小根堆,下面討論以大根堆為例子。
給定乙個列表array=[16,7,3,20,17,8],對其進行堆排序(使用大根堆)。
步驟一 構造初始堆。將給定無序序列構造成乙個大頂堆(一般公升序採用大頂堆,降序採用小頂堆)。
假設給定無序序列結構如下
此時我們從最後乙個非葉子結點開始(葉結點自然不用調整,第乙個非葉子結點 arr.length/2-1=5/2-1=1,也就是下面的6結點),從左至右,從下至上進行調整。
此處必須注意,我們把6和9比較交換之後,必須考量9這個節點對於其子節點會不會產生任何影響?因為其是葉子節點,所以不加考慮;但是,一定要熟練這種思維,寫**的時候就比較容易理解為什麼會出現一次非常重要的交換了。
找到第二個非葉節點4,由於[4,9,8]中9元素最大,4和9交換。
在真正**的實現中,這時候4和9交換過後,必須考慮9所在的這個節點位置,因為其上的值變了,必須判斷對其的兩個子節點是否造成了影響,這麼說不合適,實際上就是判斷其作為根節點的那棵子樹,是否還滿足大根堆的原則,每一次交換,都必須要迴圈把子樹部分判別清楚。
這時,交換導致了子根[4,5,6]結構混亂,繼續調整,[4,5,6]中6最大,交換4和6。
牢記上面說的規則,每次交換都要把改變了的那個節點所在的樹重新判定一下,這裡就用上了,4和9交換了,變動了的那棵子樹就必須重新調整,一直調整到符合大根堆的規則為截。
此時,我們就將乙個無序序列構造成了乙個大頂堆。
步驟二 將堆頂元素與末尾元素進行交換,使末尾元素最大。然後繼續調整堆,再將堆頂元素與末尾元素交換,得到第二大元素。如此反覆進行交換、重建、交換。
將堆頂元素9和末尾元素4進行交換
這裡,必須說明一下,所謂的交換,實際上就是把最大值從樹裡面拿掉了,剩下參與到排序的樹,其實只有總結點的個數減去拿掉的節點個數了。所以圖中用的是虛線。
重新調整結構,使其繼續滿足堆定義
再將堆頂元素8與末尾元素5進行交換,得到第二大元素8
後續過程,繼續進行調整,交換,如此反覆進行,最終使得整個序列有序
#include //交換值
void swap( int *i, int *j )
//堆排序
void heapadjust( int array, int i, int len )
else
swap( &array[i],&array[j]);
i = j;
j = 2*i+1;
}}void makeheap( int array,int n )
}void heapsort( int array, int len )
}void main()
; heapsort(a,9);
printf("排序後的結果是:");
for( i=0; i<9; i++ )
printf("\n");
}
資料結構 堆與堆排序
堆其實是從完全二叉樹演變過來的並且用來儲存資料的,什麼是完全二叉樹呢?完全二叉樹就是 若設二叉樹的深度為h,除第h層外,其它各層 1 h 1 的結點數都達到最大個數,第h層所有的結點都連續集中 在最左邊,這就是完全二叉樹。我們知道二叉樹可以用陣列模擬,堆自然也可以。現在讓我們來畫一棵完全二叉樹 從圖...
堆資料結構與堆排序
堆資料結構 堆 二叉堆 是近似的完全二叉樹,最底層允許不滿,堆的相關,陣列長度length,heap size有效長度 堆的有效元素,未排序的數目 heap size堆雖然很像二叉樹,但是我的理解就是用二叉樹的邏輯,但是最主要的區別在,堆的儲存是用陣列,只是用下標來幫助理解 堆的儲存結構 從上往下,...
資料結構與演算法 15 堆排序
3 實現 4 時間複雜度 5 穩定性 6 測試 堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序。乙個待排序的陣列,把它看成是順序儲存的二叉樹,假設要公升序排列,先把這個二叉樹調整為大頂堆,其頂端元素為最大值,把頂端元素和末尾元素互換後,再次把堆調整為大頂堆。如此迴圈,直到整個...