1. 程式人生 > >精妙的堆排序演算法

精妙的堆排序演算法

堆排序是一種不穩定的選擇排序法,但在需要排的數的基數很大的時候效率相對較高

堆排序是一種以二叉樹結構為思維框架的排序演算法

想搞懂堆排序必須先明白什麼是二叉樹,二叉樹應該怎麼畫,二叉樹中每個點與陣列每個數下標的對應關係
還有什麼是 大/小頂堆,還有堆排序的排序思路

排序思路:
先對二叉樹進行排序,使其滿足 大/小 頂堆,然後將根節點的數與陣列中最後一個數進行交換,並把交換後的最後一個數固定在那裡,之後再對除那個數以外的數進行堆排序,不斷重複上面的過程直至所有數都被固定,此時堆排序完成

在這裡插入圖片描述

#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] 22if(array[i]>array[child])

步驟總結:

  1. 找出最後一個雙親節點,先把整個二叉樹排成一個堆
  2. 把根節點與最後一個葉互換並固定
  3. 從根開始再次把剩餘未固定的部分排列成堆
  4. 不斷迴圈2.3.步直至退出

程式碼參考自:https://blog.csdn.net/YuZhiHui_No1/article/details/44258297
(程式碼中有補充別的說明)