堆排序,是一种选择排序,时间复杂度是 O(nlg(n)) ,具有空间原址性(任何时候都只需要常数个额外的元素空间存储临时数据)。同时,堆引入了另一种算法设计技巧:“堆”数据结构。
(二叉)堆是一个数组,被看成一个近似的完全二叉树。每一个节点对应数组中的一个元素,除底层外,该树为完全充满的二叉树。任何一非叶节点满足性质:
Keyi<=Key2i+1且Keyi<=Key2i+2 大顶堆
或者 Keyi>=Key2i+1且Keyi>=Key2i+2 小顶堆
矩阵 A=[16,14,10,8,7,9,3,2,4,1] 堆的表示如下(注:图片来自《算法导论》)
按常理说,应该怎样建堆,但是仔细对比,发现堆算法的核心就是保持这个堆是大顶堆(小顶堆)。建堆就是使一个堆(数组)调整成大顶堆(小顶堆),堆的排序算法也是需要不停的调整堆的。维护对通过让 A[i] 的值在最大堆(小顶堆)中“逐级下降”,从而使得以下标 i 为根节点的子树重新遵循大顶堆(小顶堆)的性质。
算法:
1、从A[i]、A[2i]和A[2i+1]中选取最大(最小)的,下标存储在largest中。
2、如果A[i]是最大的,那么以i为根结点的子树已经是最大堆,程序结束。
3、否则,最大元素是i的某个孩子借点,则交换A[i]和A[largest]的值。子树又有可能违反大顶堆(小顶堆)的性质,递归调用maxHeapify.
void swap(int* M, int i, int j){
//交换向量中的元素
int temp;
temp = M[i];
M[i] = M[j];
M[j] = temp;
}
//A[i]、A[2i]和A[2i+1]中选取最大
void maxHeapify(int* M, int i, int length){
int l = 2 * i; //左子树下标
int r = 2 * i + 1;//右子树下标
int largest;
if(l <= length && M[l]>M[i]){
largest = l;
}
else{
largest = i;
}
if(r <= length && M[r] > M[largest]){
largest = r;
}
//交换A[i]和A[largest]的值,递归调用maxHeapify.
if(largest != i){
swap(M, i, largest);
maxHeapify(M, largest, length);
}
}
建堆,使用的是自底向上的方法,利用上述维护堆程序maxHeapify把一个大小为length的数组转化为最大堆。算法是从最后一个堆(有可能只要两个结点,且根节点下标为 i1=length/2 )开始调整,调整倒数第二个堆,……,一直往上调整(第j次的根节点下标为 ij=length/2−j+1 ,直到根节点。
void buildMaxHeap(int* M, int length){
int i;
for(i = length/2; i >= 0; --i){
maxHeapify(M, i, length-1);
}
}
初始时,先利用建堆将数组建成大顶堆,将最大的值,即A[0]输出,并将堆中最后一个数放到A[0]中,调整堆使其再次变为大顶堆。直到该堆为空(下面算法中为堆的长度为0).
void heapSort(int* M, int length){
buildMaxHeap(M, length);
int i;
for(i = length; i > 0; --i){
swap(M, 0, i);
--length;
maxHeapify(M, 1, length-1);
}
}
#include "stdio.h"
void show(int M[], int length){
int i;
for(i = 0; i < length; ++i){
printf("%d ", M[i]);
}
}
//将上述代码粘贴在这里。
void main(){
int A[4] = { 2, 4, 7, 1};
int length = sizeof(A) / sizeof(A[0]);
//测试建堆
show(A, length);
printf("\n");
buildMaxHeap(A, length);
show(A, length);
printf("\n");
//测试堆排序
show(A, length);
printf("\n");
heapSort(A, length);
show(A, length);
printf("\n");
}
参考文献:
《算法导论》
《C++Primer》
http://blog.csdn.net/morewindows/article/details/6709644/
http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html