堆排序与快速排序、归并排序都是时间复杂度为O(NlogN)的常见排序算法。堆排序是一种利用堆的性质进行排序的算法。
最大堆(最小堆与之类似)是一种比较特殊的完全二叉树,它满足两个特性:
1. 父节点的值总是大于等于任何一个子节点的值。
2. 每个节点的左子树和右子树都是一个最大堆。
【若根的下标从1开始,则节点i的左孩子下标为2i,右孩子下标为2i+1】
堆排序过程为:
1. 建立最大堆
2. 将堆顶元素与最后一个元素交换,将交换后的序列调整为新堆,重复该过程,知道有序元素为n-1个
故,堆排序的基本框架为
1 void HeapSort(int a[], int size)
2 {
3 BuildHeap(a, size);
4 for(int i = size; i >= 2; i--)
5 {
6 swap(a[1], a[i]);//交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
7 HeadAdjust(a ,1 ,i-1);//重新调整,将余下元素调成大顶堆
8 }
9 }
完整代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 5 /*堆排序 6 *时间复杂度:O(NlogN) 7 *堆是完全二叉树;且有大小堆之分 8 *注意:数组从1开始,因为这样才满足;对于节点i,其左孩子是2*i,右孩子是2*i+1 9 *应用:最大堆排序用来从小到大排序数列 10 *扩展:堆经常被用来求一个数列中的第K大的数,只需要建立一个大小为K的最小堆,堆顶就是第K大的数; 11 * (如:选前k个数建最小堆,若后面的数比堆顶小,舍弃;若比堆顶大,舍弃堆顶,将数据插入 12 * 调整最小堆)!!!想清楚 13 * 求数列中第K小的数,建立大小为K的最大堆,堆顶就是第K小的数。复杂度为O(NlogK) 14 * //参见《编程之美》Chapter5的第五节 15 */ 16 17 #include "stdafx.h" 18 #include <algorithm>//std::swap() 19 #include <iostream> 20 21 using namespace std; 22 23 void HeapAdjust(int a[], int i, int size) 24 //a为堆数组,i为当前要调整的节点,以下标i为堆顶,将剩余size个元素调整为堆(即节点数为size) 25 26 { 27 int lchild = 2 * i;//i节点左右孩子节点序号 28 int rchild = 2 * i + 1; 29 int max = i;//临时变量,记录最大值的下标 30 31 if(i <= size / 2)//对叶节点i进行调整 32 { 33 if(lchild <= size && a[lchild] > a[max])//注意边界检查,包括size 34 max = lchild; 35 if(rchild <= size && a[rchild] > a[max]) 36 max = rchild; 37 if(max != i)//需调整 38 { 39 swap(a[i], a[max]); 40 HeapAdjust(a, max, size); //避免调整后以下标max为父节点的子树不是堆 41 } 42 } 43 } 44 45 /* 46 void HeapAdjust(int a[], int i, int size) 47 //堆调整非递归实现 48 { 49 a[0] = a[i];//用空闲位置a[0]临时记录当前节点的值 50 int lchild = 2 * i; 51 int max = i;//临时变量,记录最大值的下标 52 53 while( lchild <= size ) 54 { 55 if(lchild <= size && a[lchild] > a[max])//注意边界检查,包括size 56 max = lchild; 57 if((lchild + 1 <= size) && a[lchild+1] > a[max]) 58 max = lchild+1; 59 if(max == i) 60 break;//无需调整 61 else 62 { 63 //a[i] = a[max];//!! 64 swap(a[i],a[max]); 65 i = max;//!! 66 lchild = i * 2; //!! 67 } 68 } 69 //a[i] = a[0];//!!被调整节点的值被放入最终位置 70 } 71 */ 72 73 74 void BuildHeap(int a[], int size)//建堆 75 { 76 for(int i = size/2; i >= 1; --i)//非叶节点最大序号值为size/2 77 HeapAdjust(a, i, size); 78 } 79 80 void HeapSort(int a[],int size)//堆排序 81 { 82 BuildHeap(a,size); 83 for(int i=size;i>=2;--i)//到2! 84 { 85 swap(a[1],a[i]);//交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面 86 HeapAdjust(a,1,i-1);//重新调整,将余下元素调成大顶堆 87 } 88 } 89 90 int main(int argc, char *argv[]) 91 { 92 //int a[] = {0,16,20,3,11,17,8}; 93 int a[100]; 94 cout << "请输入要排序的数字个数:" ; 95 int size; 96 while(cin >> size && size>0 && size < 100) 97 { 98 for(int i=1; i <= size; ++i)//注意从下标1开始存数据 99 cin >> a[i]; 100 HeapSort(a,size); 101 for(int i=1; i <= size; ++i) 102 cout << a[i] << " "; 103 cout << endl; 104 cout << "请输入要排序的数字个数:" ; 105 } 106 return 0; 107 }
参考:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html