堆排序 heap sort
https://github.com/hotwater99/practice_datastructure_and_algorithm.git
《数据结构与算法分析——C语言描述》机械工业出版社,原书第2版,7.5节
https://blog.csdn.net/u010452388/article/details/81283998
另外这个动图也可以帮助理解:
https://www.jianshu.com/p/0d383d294a80
堆排序分为两步:
1、把待排序的数组(N个元素)变成一个Max堆;
2、数组分为两部分,前一部分为堆空间(初始大小N),后一部分为排序空间(初始大小0);
3、取出堆顶的数,即堆空间的第一个数A[堆顶]与最后一个数B交换,堆空间-1,同时A进入排序空间(因为每次取出的都是堆中最大的数,交换后的位置也是连续的),排序空间+1;
4、剩下的数再重新构造成Max堆,即将B在堆中下滤;
5、最后得到的数组就变成了从小到大排列的有序数组。
堆排序:
1 #define LeftChild(i) (2 * (i) + 1) 2 3 void PercDown(int array[], int i, int N) 4 { 5 int child; 6 int tmp; 7 8 for (tmp = array[i]; LeftChild(i) < N; i = child) { 9 child = LeftChild(i); 10 if (child + 1 < N && array[child + 1] > array[child]) { 11 child++; 12 } 13 if (tmp < array[child]) { 14 array[i] = array[child]; 15 } 16 else { 17 break; 18 } 19 } 20 array[i] = tmp; 21 } 22 23 void Swap(int *a, int *b) 24 { 25 int tmp = *a; 26 *a = *b; 27 *b = tmp; 28 } 29 30 void HeapSort(int array[], int N) 31 { 32 int i; 33 34 // build heap 35 for (i = N / 2; i >= 0; i--) { 36 PercDown(array, i, N); 37 } 38 // delete max 39 for (i = N - 1; i > 0; i--) { 40 Swap(&array[0], &array[i]); 41 PercDown(array, 0, i); 42 } 43 }
void PercDown(int array[], int i, int N) 的功能是把array[i]这个元素下滤。
构造Max堆:array[0]到array[N/2]将是非叶子节点,array[N/2]之后的将是叶子节点(不一定是在堆的最后一层,但都是叶子节点)。所以从非叶子节点开始处理,且从下往上,从右到左,即35行中i从N/2开始递减。
删除最大数:交换堆顶array[0]--a和array[i]--b,堆顶a放到array[i],array[i]之后就不属于堆了,完成了从堆中删除最大数的操作,同时因为每次取出的都是堆中最大数,i也是从N-1开始递减,这样也完成了排序的工作;之后对b进行一次下滤操作,完成了重新构造Max堆的操作。
1 #include <iostream> 2 #include <ctime> 3 4 using namespace std; 5 6 #define random(x) (rand()%x) 7 #define ARRAY_LENTH 100000 8 9 #define LeftChild(i) (2 * (i) + 1) 10 11 void PercDown(int array[], int i, int N) 12 { 13 int child; 14 int tmp; 15 16 for (tmp = array[i]; LeftChild(i) < N; i = child) { 17 child = LeftChild(i); 18 if (child + 1 < N && array[child + 1] > array[child]) { 19 child++; 20 } 21 if (tmp < array[child]) { 22 array[i] = array[child]; 23 } 24 else { 25 break; 26 } 27 } 28 array[i] = tmp; 29 } 30 31 void Swap(int *a, int *b) 32 { 33 int tmp = *a; 34 *a = *b; 35 *b = tmp; 36 } 37 38 void HeapSort(int array[], int N) 39 { 40 int i; 41 42 // build heap 43 for (i = N / 2; i >= 0; i--) { 44 PercDown(array, i, N); 45 } 46 // delete max 47 for (i = N - 1; i > 0; i--) { 48 Swap(&array[0], &array[i]); 49 PercDown(array, 0, i); 50 } 51 } 52 53 int main() { 54 int test_array[ARRAY_LENTH]; 55 int i, N = ARRAY_LENTH; 56 clock_t start_time, stop_time; 57 58 for (i = 0; i < N; i++) { 59 test_array[i] = random(N); 60 } 61 62 cout << "raw : "; 63 for (i = 0; i < N; i++) { 64 cout << test_array[i] << " "; 65 } 66 cout << endl; 67 68 start_time = clock(); 69 70 HeapSort(test_array, N); 71 72 stop_time = clock(); 73 74 cout << "sort: " ; 75 for (i = 0; i < N; i++) { 76 cout << test_array[i] << " "; 77 } 78 cout << endl; 79 80 cout << "HeapSort(" << N << ")..." << endl; 81 cout << "total time used: "; 82 cout << (double)(stop_time - start_time) / CLOCKS_PER_SEC << "s" << endl; 83 84 system("pause"); 85 86 return 0; 87 }
测试结果
N=10
raw : 1 7 4 0 9 4 8 8 2 4 sort: 0 1 2 4 4 4 7 8 8 9 HeapSort(10)... total time used: 0s
N=100
raw : 41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 91 4 2 53 92 82 21 16 18 95 47 26 71 38 69 12 67 99 35 94 3 11 22 33 73 64 41 11 53 68 47 44 62 57 37 59 23 41 29 78 16 35 90 42 88 6 40 42 64 48 46 5 90 29 70 50 6 1 93 48 29 23 84 54 56 40 66 76 31 8 44 39 26 23 37 38 18 82 29 41 sort: 0 1 2 3 4 5 5 6 6 8 11 11 12 16 16 18 18 21 22 23 23 23 24 26 26 27 27 29 29 29 29 31 33 34 35 35 36 37 37 38 38 39 40 40 41 41 41 41 42 42 42 44 44 45 46 47 47 48 48 50 53 53 54 56 57 58 59 61 62 62 64 64 64 66 67 67 68 69 69 70 71 73 76 78 78 81 82 82 84 88 90 90 91 91 92 93 94 95 95 99 HeapSort(100)... total time used: 0s
N=1000
HeapSort(1000)... total time used: 0s
N=10000
HeapSort(10000)... total time used: 0.001s
N=100000
HeapSort(100000)... total time used: 0.017s