八大排序演算法~堆排序
阿新 • • 發佈:2021-07-25
八大排序演算法~堆排序
1,思想:就是利用堆資料結構特點進行排序【堆結構特點~完全二叉樹,而咱排序主要是利用(大根堆或者小根堆特點進行排序)】
【小根堆】:每一個父結點的值都比子結點小,因為每個父節點都比子結點小,咱知道 小根堆的最小值就在根結點;
【大根堆】:每一個父結點的值都比子結點大,因為每個父節點都比子結點大,咱知道 大根堆的最大值就在根結點;
(補充一下,因為小根堆要求只是父結點大於子結點,沒有要求左右結點的大小關係噢,大根堆也是哈,咱對左右結點大小關係沒有關係哈)
2,接下來,咱以大根堆排序為例,講述好堆排序過程:
我覺得它的思想有些類似於咱總結的“冒泡思想”~
冒泡思想~(從小到大排序哈)【後座就認為是後邊哈,沒有啥特別,叫後座主要是為了強調後邊啦】
氣泡排序思想:從第一個數開始找,要把大數“排除在外”~為大數找後座。(從小到大排序哈) 外層迴圈~需要放後的大數個數; 內迴圈~從第一個數拿起與後面位置的數兩兩比較,實力強的佔的位置靠後。
堆排序思想~(從小到大排序哈)~剛好藉助大根堆的特點進行排序
堆排序(藉助大根堆,實現從小到大排序)思想: 咱對n個結點構建成一個大根堆,然後取根結點(最大值“排除在外”~放到後座上最後一個位置), 咱在對剩餘的n-1個結點構建成一個新的大根堆,然後又取根結點放到後座上倒數第二個位置, 然後對剩餘的n-2個結點構建成一個新的大根堆,然後又取根結點放到後座上倒數第三個位置, ........ 直到剩下一個結點結束。
//過程:(1)建立成大根堆,
(2)for迴圈(從 i=最後一個結點位置開始直到i=第一個結點 結束):取根結點放於後座~即進行交換,根結點與後座最後一個位置進行交換,然後重構成新的大根堆,
再取根節點跟後座倒數第二個位置交換,然後重新構建新的大根堆,然後。。。
ps:本菜菜小白想請問,為什麼要先初始化堆,然後for迴圈 取根結點,重新調整成堆;
為什麼不能for迴圈 調整成堆,然後取根結點,然再次調整成堆,然後再取根結點,再調整成堆。。。。
就是為什麼要單獨初始化堆,不把它寫到迴圈裡?
3,程式碼:引自~《【演算法】排序演算法之堆排序》~https://zhuanlan.zhihu.com/p/124885051
【這個 “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; }