精妙的堆排序演算法
阿新 • • 發佈:2018-12-13
堆排序是一種不穩定的選擇排序法,但在需要排的數的基數很大的時候效率相對較高
堆排序是一種以二叉樹結構為思維框架的排序演算法
想搞懂堆排序必須先明白什麼是二叉樹,二叉樹應該怎麼畫,二叉樹中每個點與陣列每個數下標的對應關係
還有什麼是 大/小頂堆,還有堆排序的排序思路
排序思路:
先對二叉樹進行排序,使其滿足 大/小 頂堆,然後將根節點的數與陣列中最後一個數進行交換,並把交換後的最後一個數固定在那裡,之後再對除那個數以外的數進行堆排序,不斷重複上面的過程直至所有數都被固定,此時堆排序完成
#include<stdio.h> //從小到大排序,應用大頂堆
#define LEN 12//排序的數字個數
void print_array(int *array, int length) //列印陣列
{
int index = 0;
printf("array:\n");
for(; index < length; index++){
printf(" %d,", *(array+index));
}
printf("\n\n");
}
void _heapSort(int *array, int i, int length) //堆化函式
{
int child, tmp;
//這個是改變了哪個節點,就從該節點開始對以該節點為根節點的子樹進行排序
for (; 2*i + 1 < length; i = child){//依次到它的子樹的子樹。。。。從那個節點到其的子節點不斷交換
child = 2*i + 1;//左子節點
if ((child +1 < length)/*為了防止此葉的父節點只有一個子節點*/ && (array[child+1] > array[child])) child++;//選個最大的孩子節點
if (array[i] < array[ child]){//最大子節點和父節點進行互動
tmp = array[i];
array[i] = array[child];
array[child] = tmp;
}else break;//不用交換或往後沒有子節點則退出
}
}
void heapSort(int *array, int length)
{
int i, tmp;
if (length <= 1) return;//如果元素小於等於1,則退出
//這一步是先把元素都堆化好,後面的話 哪個節點修改過,就從哪個節點開始對以它為根節點的子樹進行堆化
for (i = length/2 - 1; i >= 0; i--) _heapSort(array, i, length);//從最後一個非葉子節點(雙親節點)開始堆化,一直到根節點
// 先抽取到根節點,與最後一個葉互換位置並定住。然後再對元素進行堆化,然後又抽取根節點,再對元素進行堆化...依次迴圈
for (i = 0; i < length; i++ ){
tmp = array[0];
array[0] = array[length-i-1];
array[length -i-1] = tmp;
_heapSort(array, 0, length-1-i);//堆化子樹
}
}
int main(void)
{
int array[LEN] = {2, 1, 4, 0, 12, 520, 2, 9, 5, 3, 13, 14};
print_array(array, LEN);//列印排序前的陣列
heapSort(array, LEN);//堆排序
print_array(array, LEN);//列印排序後的陣列(從小到大)
return 0;
}
如果想要排從大到小,則把21,22行修改為:
21:array[child+1] < array[child]
22:if(array[i]>array[child])
步驟總結:
- 找出最後一個雙親節點,先把整個二叉樹排成一個堆
- 把根節點與最後一個葉互換並固定
- 從根開始再次把剩餘未固定的部分排列成堆
- 不斷迴圈2.3.步直至退出
程式碼參考自:https://blog.csdn.net/YuZhiHui_No1/article/details/44258297
(程式碼中有補充別的說明)