经典排序之 堆排序
下面来说一下堆排序,这个有点复杂;
堆是一种数据结构,可以把它看成一棵完全二叉树,这棵完全二叉树满足任何一个非叶子节点的值都不大于或不小于其左右孩子节点的值,分别叫做大顶堆和小顶堆。
算法思想:
堆排序的算法分为两步:建立堆和排序;
1)建堆:
将序列调整为大顶堆,每一次都是父节点和子节点进行比较然后进行调整;
2)排序:
在已经建好的大顶堆的前提下,将根节点的元素和后边的元素交换,再调整直到最后;
这样堆排序每次都会有一个元素位于其最终的位置。堆排序适合数据量很大的情况下,典型的例子是在1000000个数据中选出最小的前10个。堆排序的最好,最坏,和平均的时间复杂度均是O(n*lgn)。它是一种不稳定的排序。
算法实现:
1 #include<iostream> 2 using namespace std; 3 4 void swap(int &a, int &b){ 5 int temp = a; 6 a = b; 7 b = temp; 8 } 9 10 void adjustShift(int *data, int low, int high){ //建堆 11 int i = low, j = 2 * i + 1; //数据从下标0开始 12 int temp = data[i]; 13 14 while(j <= high){ //若右孩子大,则调整 15 if(j < high && data[j] < data[j + 1]){ 16 ++j; 17 } 18 19 if(temp < data[j]){ 20 data[i] = data[j]; 21 i = j; 22 j = 2 * i + 1; 23 } 24 25 else{ 26 break; 27 } 28 } 29 30 data[i] = temp; 31 } 32 33 void headSort(int *data, int length){ //排序 34 int i, temp; 35 36 for(i = length / 2 ; i >= 0; --i){ //建立初始堆 37 adjustShift(data, i, length ); 38 } 39 40 for(i = length; i >= 1; i--){ //进行n-1次循环,完成排序 41 swap(data[0], data[i]); 42 adjustShift(data, 0, i - 1); 43 } 44 } 45 46 int main(){ //测试程序 47 int str[] = {23, 34, 2, 0, 56, 89, 5, 8, 13}; 48 int len = sizeof(str) / sizeof(int); 49 50 headSort(str, len - 1); 51 52 for(int k = 0; k < len; k++){ 53 cout<<str[k]<<' '; 54 } 55 56 return 0; 57 }
下边 的图示过程: