八大排序算法~堆排序算法
1,思想:就是利用堆數據結構特色進行排序【堆結構特色~徹底二叉樹,而咱排序主要是利用(大根堆或者小根堆特色進行排序)】api
【小根堆】:每個父結點的值都比子結點小,由於每一個父節點都比子結點小,咱知道 小根堆的最小值就在根結點;數據結構
【大根堆】:每個父結點的值都比子結點大,由於每一個父節點都比子結點大,咱知道 大根堆的最大值就在根結點;
函數
(補充一下,由於小根堆要求只是父結點大於子結點,沒有要求左右結點的大小關係噢,大根堆也是哈,咱對左右結點大小關係沒有關係哈)
動畫
2,接下來,咱以大根堆排序爲例,講述好堆排序過程:spa
我以爲它的思想有些相似於咱總結的「冒泡思想」~code
冒泡思想~(從小到大排序哈)【後座就認爲是後邊哈,沒有啥特別,叫後座主要是爲了強調後邊啦】blog
冒泡排序思想:從第一個數開始找,要把大數「排除在外」~爲大數找後座。(從小到大排序哈) 外層循環~須要放後的大數個數; 內循環~從第一個數拿起與後面位置的數兩兩比較,實力強的佔的位置靠後。
堆排序思想~(從小到大排序哈)~恰好藉助大根堆的特色進行排序排序
堆排序(藉助大根堆,實現從小到大排序)思想: 咱對n個結點構建成一個大根堆,而後取根結點(最大值「排除在外」~放到後座上最後一個位置), 咱在對剩餘的n-1個結點構建成一個新的大根堆,而後又取根結點放到後座上倒數第二個位置, 而後對剩餘的n-2個結點構建成一個新的大根堆,而後又取根結點放到後座上倒數第三個位置, ........ 直到剩下一個結點結束。
//過程:(1)創建成大根堆,
(2)for循環(從 i=最後一個結點位置開始直到i=第一個結點 結束):取根結點放於後座~即進行交換,根結點與後座最後一個位置進行交換,而後重構成新的大根堆,
再取根節點跟後座倒數第二個位置交換,而後從新構建新的大根堆,而後。。。
ps:本菜菜小白想請問,爲何要先初始化堆,而後for循環 取根結點,從新調整成堆;
爲何不能for循環 調整成堆,而後取根結點,然再次調整成堆,而後再取根結點,再調整成堆。。。。
就是爲何要單獨初始化堆,不把它寫到循環裏?
3,代碼:引自~《【算法】排序算法之堆排序》~https://zhuanlan.zhihu.com/p/124885051it
【這個 「developer1024 」 做者大大這篇文章裏的動畫可讓你秒懂堆排的】
#include <stdio.h> #include <stdlib.h> void swap(int* a, int* b) { int temp = *b; *b = *a; *a = temp; } void max_heapify(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], &arr[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--) max_heapify(arr, i, len - 1); //先將第一個元素和已排好元素前一位作交換,再重新調整,直到排序完畢 for (i = len - 1; i > 0; i--) { swap(&arr[0], &arr[i]); max_heapify(arr, 0, i - 1); } } int main() { int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 }; int len = (int) sizeof(arr) / sizeof(*arr); heap_sort(arr, len); int i; for (i = 0; i < len; i++) printf("%d ", arr[i]); printf("\n"); return 0; }