天天看點

資料結構與算法——十個排序算法之七 · 堆排序

堆排序(Heapsort)是指利用堆這種資料結構所設計的一種排序算法,它是選擇排序的一種。可以利用數組的特 點快速定位指定索引的元素.

堆積是一個近似完全二叉樹的結構,并同時滿足堆積的性質:即子結點的鍵值或索引總是小于(或者大于)它的父節點。堆排序可以說是一種利用堆的概念來排序的選擇排序。分為兩種方法:

  1. 大頂堆:每個節點的值都大于或等于其子節點的值,在堆排序算法中用于升序排列;
  2. 小頂堆:每個節點的值都小于或等于其子節點的值,在堆排序算法中用于降序排列;

堆排序的平均時間複雜度為 Ο(nlogn)

(選擇排序工作原理 - 第一次從待排序的資料元素中選出最小(或最大)的一個元素,存放在序列的起始位置, 然後再從剩餘的未排序元素中尋找到最小(大)元素,然後放到已排序的序列的末尾。以此類推,直到全部待 排序的資料元素的個數為零)

1. 排序核心實作

資料結構與算法——十個排序算法之七 · 堆排序

 2. 算法步驟

  1. 建立一個堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互換;
  3. 把堆的尺寸縮小 1,并調用 shift_down(0),目的是把新的數組頂端資料調整到相應位置;
  4. 重複步驟 2,直到堆的尺寸為 1。

3. 動圖示範(來源 runoob.com):

資料結構與算法——十個排序算法之七 · 堆排序
資料結構與算法——十個排序算法之七 · 堆排序

3. 具體算法實作

1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 typedef struct _Heap
  6 {
  7     int *arr; //存儲堆元素的數組
  8     int size; //目前已存儲的元素個數
  9     int capacity; //目前存儲的容量
 10 }Heap;
 11 
 12 bool initHeap(Heap &heap, int *orginal, int size);
 13 bool popMax(Heap &heap, int &value);
 14 void heapSort(Heap &heap);
 15 static void buildHeap(Heap &heap);
 16 static void adjustDown(Heap &heap, int index);
 17 
 18 /*初始化堆*/
 19 bool initHeap(Heap &heap, int *orginal, int size)
 20 {
 21     //heap.arr = new int[capacity];
 22     heap.arr = orginal;
 23     if (!heap.arr) return false;
 24 
 25     heap.capacity = size;
 26     heap.size = size;
 27 
 28     //如果存在原始資料則建構堆
 29     if(size > 0)
 30     {
 31         //方式一: 直接調整所有元素
 32         //建堆
 33         buildHeap(heap);
 34     }
 35     return true;
 36 }
 37 
 38 /* 從最後一個父節點(size/2-1 的位置)逐個往前調整所有父節點(直到根節點), 確定每一個父節點都是一個最大堆,最後整體上形成一個最大堆 */
 39 void buildHeap(Heap &heap)
 40 {
 41     int i;
 42     for (i = heap.size / 2 - 1; i >= 0; i--)
 43     {
 44         adjustDown(heap, i);
 45     }
 46 }
 47 
 48 /*将目前的節點和子節點調整成最大堆*/
 49 void adjustDown(Heap &heap, int index)
 50 {
 51     int cur = heap.arr[index];            //目前待調整的節點
 52     int parent, child;
 53 
 54     /*判斷否存在大于目前節點子節點,如果不存在 ,則堆本身是平衡的,不需要調整;
 55     如果存在,則将最大的子節點與之交換,交換後,如果這個子節點還有子節點,則要繼續
 56     按照同樣的步驟對這個子節點進行調整*/
 57     for (parent = index; (parent * 2 + 1)<heap.size; parent = child)
 58     {
 59         child = parent * 2 + 1;
 60         //取兩個子節點中的最大的節點
 61         if (((child + 1)<heap.size) && (heap.arr[child]<heap.arr[child + 1]))
 62         {
 63             child++;
 64         }
 65         //判斷最大的節點是否大于目前的父節點
 66         if (cur >= heap.arr[child])
 67         {
 68             //不大于,則不需要調整,跳出循環
 69             break;
 70         }
 71         else
 72         {
 73             //大于目前的父節點,進行交換,然後從子節點位置繼續向下調整
 74             heap.arr[parent] = heap.arr[child];
 75             heap.arr[child] = cur;
 76         }
 77     }
 78 }
 79 
 80 /* 實作堆排序 */
 81 void heapSort(Heap &heap)
 82 {
 83     if (heap.size<1) return ;
 84     while(heap.size>0)
 85     {
 86         int tmp = heap.arr[0];
 87         heap.arr[0] = heap.arr[heap.size-1];
 88         heap.arr[heap.size-1] = tmp;
 89         heap.size--;
 90         adjustDown(heap, 0);// 向下執行堆調整
 91     }
 92 }
 93 
 94 /* 删除最大的節點,并獲得節點的值*/
 95 bool popMax(Heap &heap, int &value)
 96 {
 97     if (heap.size<1) return false;
 98     value = heap.arr[0];
 99     heap.arr[0] = heap.arr[--heap.size];
100     //heap.arr[0] = heap.arr[heap.size-1];
101     //heap.size--;
102     adjustDown(heap, 0);// 向下執行堆調整
103     return true;
104 }
105 
106 int main(void)
107 {
108     Heap hp;
109     int origVals[] = { 1, 2, 3, 87, 93, 82, 92, 86, 95 };
110     int i = 0;
111     if(!initHeap(hp, origVals, sizeof(origVals)/sizeof(origVals[0])))
112     {
113         fprintf(stderr, "初始化堆失敗!\n");
114         exit(-1);
115     }
116 
117     for (i = 0; i<hp.size; i++)
118     {
119         printf("the %dth element:%d\n", i, hp.arr[i]);
120     }
121 
122     //執行堆排序
123     heapSort(hp);
124     printf("堆排序後的結果:\n");
125     for(i=0; i<sizeof(origVals)/sizeof(origVals[0]); i++)
126     {
127         printf(" %d", origVals[i]);
128     }
129 
130     system("pause");
131     return 0;
132 }      

==================================================================================================================