堆排序
1 什麼是堆
堆的定義
把這個關係 和完全二叉樹對應起來,如下圖,如果 下標 從1 開始, 這 任意一個節點 i 2i +1 2i +2
對於小標從 i ==1 下標從0開始i ==0 的情況
來看下 下面 是 不是堆 ?
左面 是 小頂堆 ; 右面是 大頂堆
看看下面的圖形
左邊 3 6 7 不滿足 大頂堆的定義, 中間 大頂堆 右面 是 大頂堆
2 堆的存儲的結構
圖1 爲 實際 存儲結構 , 圖2 右面 放在 完全二叉樹中的邏輯結構。
3 如何建立 大頂堆
用上面的結構爲例 進行圖解
此時建立 了 大頂堆, 將 第0 個元素的 待排序列中的最後一個位置互換位置。 之後對 0 —> 12 進行 最大堆調整 即可,
直到i==0 時候, 待排 序列 就全部完成, 此時 arr[] 排成的 升序啦。。
4 開始 調整堆
5 堆排序的過程
堆排序的過程是:
(1)建立一個堆array[0…n-1]。
(2)把堆首(最大值)和堆尾互換。
(3)把堆的尺寸縮小1,然後調整堆,目的構成新的堆。
(4)重複步驟2,直到堆的尺寸爲1,排序完成。
#include <stdio.h>
/* 交換元素 */
void swap (int array[], int i, int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
void printAaray(int array[] ,int len){
for(int i=0; i < len; i++){
printf("%d ", array[i]);
}
printf("\n");
}
/* 調整堆 */
void heap_ajust(int arr[], int start, int end) {
//建立父節點下標和子節點下標
int dad = start;
int son = dad * 2 + 1;
while (son <= end) { //
if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節點大小,選擇最大的
son++;
if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數
return;
else { //否則交換父子內容再繼續子節點和孫節點比較
swap(arr,dad,son);
dad = son;
son = dad * 2 + 1;
}
}
}
/* 堆排序 */
void heap_sort(int arr[], int len) {
int i;
//初始化堆,i從最後一個父節點開始調整
// 建立最大堆
for (i = len / 2 - 1; i >= 0; i--) {
heap_ajust(arr, i, len - 1);
}
//先將第一個元素和已排好元素前一位做交換,再從新調整,直到排序完畢
for (i = len - 1; i > 0; --i) {
swap(arr,0,i);
heap_ajust(arr, 0, i-1);
}
}
int main(int argc, char const *argv[]) {
int arr[]={1,34,6,21,98,31,7,4,36,47,39,45,5,2};
int length = sizeof(arr) / sizeof(int);
/* sort */
heap_sort(arr, length);
/* print Array */
printAaray(arr,length);
return 0;
}
同理 一直這樣調整 堆 把調整成 大頂堆, 之後將堆頂的元素和待排序列的最後的一個元素 互換值,之後 帶排序序列減1 , 已排序列 加1 。
最後 i ==0 ,此時就剩一個 待排序列 ,也就完成了所有的排序。