看了左神的堆排序,以爲思路很清晰,比常見的遞歸的堆排序要更容易理解,因此本身整理了一下筆記,帶你們一步步實現堆排序算法算法
首先介紹什麼是大根堆:每個子樹的最大值都是子樹的頭結點,即根結點是全部結點的最大值api
堆排序是基於數組和二叉樹思想實現的(二叉樹是腦補結構,實際是數組)數組
堆排序過程spa
一、數組建成大根堆,首先,遍歷全部結點,當前結點index和父結點(index-1)/ 2 比較 (當前數組的下標是index,此結點的父結點的下標就是(index-1)/ 2 ),若是比父結點大,交換,變成父結點的位置再和上一層的父結點比較,直到知足大根堆條件設計
int swap(int source[], int a, int b) { int temp = source[a]; source[a] = source[b]; source[b] = temp; } int heapsort(int source[], int len) { for (int i = 0; i <len; i++) { heapInsert(source, i); } } int heapInsert(int source[], int index) { while (source[index] > source[(index - 1) / 2]) { swap(source, index, (index - 1) / 2); index = (index - 1) / 2; } }
二、讓根結點和最後一個結點交換位置,也就是數組的第一個數和最後一個數交換位置,接下來最後一個數不用考慮了,好比一個數組有5個數,定義一個變量size=5,大根堆的根結點放到最後一個數後,--sizecode
int size = len; swap(source, 0, --size);
三、讓交換後的頭結點經歷一個向下的調整,讓結點和本身的兩個孩子比較,若是孩子的值比頭結點大,交換,交換到孩子結點位置,繼續和下面的兩個孩子比較,直到知足大根堆條件blog
int heapify(int source[], int index, int size)//index表示要和它兩個孩子比較的結點 { int left = index * 2 + 1; //找到index左孩子結點的數組下標 while (left < size) { int largest = left + 1 < size && source[left + 1] > source[left] ? source[left + 1] : source[left];//若是有右孩子且右孩子比左孩子大,令largest=右孩子的值,也就是把兩個孩子中最大的一個數賦給largest if (source[index] < source[largest]) { swap(source, index, largest); index = largest; left = index * 2 + 1; } else break; } }
四、重複第2步,第3步,直到size = 0 ,整個數組排序過程結束排序
while (size > 0) { swap(source, 0, --size); heapify(source, 0, size); }
源代碼以下遞歸
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> int swap(int source[], int a, int b) { int temp = source[a]; source[a] = source[b]; source[b] = temp; } int heapsort(int source[], int len) { for (int i = 0; i < len; i++) { heapInsert(source, i); } int size = len; while (size > 0) { swap(source, 0, --size); heapify(source, 0, size); } } int heapInsert(int source[], int index) { while (source[index] > source[(index - 1) / 2]) { swap(source, index, (index - 1) / 2); index = (index - 1) / 2; } } int heapify(int source[], int index, int size)//index表示要和它兩個孩子比較的結點 { int left = index * 2 + 1; //找到index左孩子結點的數組下標 while (left < size) { int largest = left + 1 < size && source[left + 1] > source[left] ? left + 1 : left;//若是有右孩子且右孩子比左孩子大,令largest=右孩子的值,也就是把兩個孩子中最大的一個數賦給largest if (source[index] < source[largest]) { swap(source, index, largest); index = largest; left = index * 2 + 1; } else break; } } int main() { int source[] = { 10,16,123,8,79,6,54,65,48,6,54,536,654,64,8,9,25,17 }; int len; len = sizeof(source) / sizeof(int); heapsort(source, len); for (int i = 0; i < len; i++) { printf("%d ", source[i]); } }
輸出結果string
以上就是堆排序的全部細節,這個版本很優良,堆排序的額外空間複雜度是O(1),若是用遞歸的話,遞歸有遞歸棧,額外空間複雜度不就上去了嗎,設計成這種迭代的能夠省空間,時間複雜度爲O(n log n)
轉載請註明出處、做者 謝謝