堆排序
堆排序(Heapsort)是利用堆這種數據結構所設計的一種排序算法, 它是選擇排序的一種. 可以利用數組的特點快速定位索引的元素.
(選擇排序工作原理 - 第一次從待排序的數據元素中選出最小(或最大)的一個元素, 存放在序列的起始位置, 然後再從剩餘的未排序元素中尋求到最小(大)元素, 然後放到已排序的尾部. 以此類推, 直到全部待排序的數據元素的個數爲零)
其排序核心實現如下:
第一步:
第二步:
先變爲最大堆先, 再執行第一步.
重複上面的兩個步驟
參考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _Heap
{
int* arr; /* 存儲堆元素的數組 */
int size; /* 當前已存儲的元素個數 */
int capacity; /* 當前存儲的容量 */
}Heap;
bool initHeap(Heap& heap, int* orginal, int size);
void buildHeap(Heap& heap);
void adjustDown(Heap& heap, int index);
void heapSort(Heap& heap);
bool popMax(Heap& heap, int& value);
/* 初始化堆 */
bool initHeap(Heap& heap, int* orginal, int size)
{
heap.arr = orginal;
if (!heap.arr) return false;
heap.capacity = size;
heap.size = size;
/* 如果存在原始數據則構建堆 */
if (size > 0)
{
/* 方式一: 直接調整所有元素(建堆) */
buildHeap(heap);
}
return true;
}
/* 從最後一個父節點(size/2-1的位置)逐個往前調整所有父節點(直到根結點),
** 確保每個父節點都是一個最大堆, 最後整體形成一個最大堆
*/
void buildHeap(Heap& heap)
{
int i;
for (i = heap.size / 2 - 1; i >= 0; i--)
{
adjustDown(heap, i);
}
}
/* 將當前的節點和子節點調整成最大堆 */
void adjustDown(Heap& heap, int index)
{
int cur = heap.arr[index]; /* 當前待調整的節點 */
int parent, child;
/* 判斷是否存在大於當前節點子節點, 如果不存在, 則堆本身是平衡的, 不需要調整;
如果存在, 則將最大的子節點與之交換, 交換後, 如果這個子節點還有子節點, 則要繼續
按照同樣的步驟對這個子節點進行調整 */
for (parent = index; (parent * 2 + 1) < heap.size; parent = child)
{
child = parent * 2 + 1;
/* 取兩個字節點中最大的節點 */
if (((child + 1) < heap.size) && ((heap.arr[child]) < heap.arr[child + 1]))
{
child++;
}
/* 判斷最大的節點是否大於當前的父節點 */
if (cur >= heap.arr[child]) /* 不大於, 則不需要調整, 跳出循環 */
{
break;
}
else /* 大於當前的父節點, 進行交換, 然後從子節點位置繼續向下調整 */
{
heap.arr[parent] = heap.arr[child];
heap.arr[child] = cur;
}
}
}
/* 實現堆排序 */
void heapSort(Heap& heap)
{
if (heap.size < 1) return;
while (heap.size > 0)
{
int tmp = heap.arr[0];
heap.arr[0] = heap.arr[heap.size - 1];
heap.arr[heap.size - 1] = tmp;
heap.size--;
adjustDown(heap, 0); /* 向下執行堆調整 */
}
}
/* 刪除最大的節點, 並獲得節點的值 */
bool popMax(Heap& heap, int& value)
{
if (heap.size < 1) return false;
value = heap.arr[0];
heap.arr[0] = heap.arr[--heap.size];
adjustDown(heap, 0); /* 向下執行堆調整 */
return true;
}
int main()
{
Heap hp;
int origVals[] = { 1,2,3,87,93,82,92,86,95 };
int i = 0;
if (!initHeap(hp, origVals, sizeof(origVals) / sizeof(origVals[0])))
{
fprintf(stderr, "初始化堆失敗!\n");
exit(-1);
}
for (i = 0; i < hp.size; i++)
{
printf("the %dth elemennt: %d\n", i, hp.arr[i]);
}
/* 執行堆排序 */
heapSort(hp);
printf("執行堆排序後的結果: \n");
for (i = 0; i < sizeof(origVals) / sizeof(origVals[0]); i++)
{
printf(" %d", origVals[i]);
}
system("pause");
return 0;
}
運行環境: vs 2019
運行結果:
結語:
學到的知識要, 多複習, 多總結, 多敲. 需要時間的積累, 才能引起質的改變. 自己寫不出來的永遠是別人的.
分享一下我的技巧: 代數法把具體的數字帶進去, 看看能能能找到規律(掌握思想).
還有就是畫圖, 也很重要. 用筆畫出來, 把數代進去, 方法雖然笨, 但真的很實用, 好記憶不如爛筆頭!!! 還有多用debug(調試工具)
我是小白, C/C++功力…, 你懂得, 寫的文章可能不是很好. 如果存在問題, 歡迎大神給予評判指正.
錯了不可怕, 可怕的是找不出bug, 誰沒錯過!!!
最近學操作系統我認爲, 學什麼都要成本(時間), 即使它是免費的, 我個人認爲要挑來學, 挑重點來學, 而不是從頭到尾, 除非考試考研.
這個知識點我沒有完全掌握, 就是會了也要複習, 革命尚未成功, 同志還需努力!!! , 我會回來反覆複習的
今日是: 2020年5月18日, (由於疫情的原因)現在沒有返校. 寫博客,也可自己加強記憶,就當寫寫日記吧!!!
希望給個贊: 反正你又不虧, 順便而已