堆排序(Heap sort),是利用数据结构堆(Heap)来对数列进行排序的方法。
堆类似于一种完全二叉树,其元素分布在一个数组之中,不同的树节点编号对应不同的数组索引号。
比如:数组10 6 3 7 2 8 9 2 4 1 对应的堆形状类似于:
总结起来,就是父节点 i 的左子节点在位置 (2*i);父节点 i 的右子节点在位置 (2*i+1);子节点 i 的父节点在位置 floor(i/2);C/C++中,父节点 i 的左子节点在位置 (2*i+1);父节点 i 的右子节点在位置 (2*i+2);子节点 i 的父节点在位置 floor((i-1)/2)。
但上图并不是一个堆,因为对要满足父节点的值要始终不大于子节点(小根堆)或者始终不小于子节点(大根堆)。
因此要得到上图对应的堆(大根堆),需要对所有的父节点(满足 i*2 +1 < last 的节点 i)进行堆化(heapify)操作,使得最后的结果满足堆的要求。
最后得到的堆如下图:
对应的数组结构为: 10 7 9 6 2 8 3 2 4 1
得到对结构以后,就可以进行堆排序了。
因为堆的根节点始终是未排序区的最大元素,所以可以循环地将堆顶元素与最后的未排序元素交换。每一次将最后面的元素(最后一个叶节点)与根节点交换,得到了一个近似堆和后面一个有序部分。对除有序部分之外的近似堆进行堆化处理又生成了一个新堆,从而又可以进行新的过程了。
算法如下:
首先,堆原始数组进行建堆操作。
然后,i = 1,i < n-1,
然后,将 d[0] 与 d[n-i] 交换,对前(n-i)个元素组成的近似堆进行堆化操作
然后,i++
然后重复上两步,一直到数组有序。
实现代码如下:
void heapify(double *dataIn, int index, int sizeIn)
{/* 2012/08/24, by wbprime@myopera.com */
int lChild = index * 2 + 1,
rChild = index * 2 + 2;
int iParent = index;
if(lChild < sizeIn && dataIn[lChild] > dataIn[iParent]) {
iParent = lChild;
}
if(rChild < sizeIn && dataIn[rChild] > dataIn[iParent]) {
iParent = rChild;
}
if (iParent != index) {
swap(dataIn[iParent], dataIn[index]);
heapify(dataIn, iParent, sizeIn);
}
}
void buildHeap(double *dataIn, int sizeIn)
{/* 2012/08/24, by wbprime@myopera.com */
for (int i = (sizeIn-2)/2; i >= 0; i--) {
heapify(dataIn, i, sizeIn);
}
}
void heapSort(double *dataIn, int sizeIn)
{/* 2012/08/24, by wbprime@myopera.com */
/* first build a heap */
buildHeap(dataIn, sizeIn);
/* then exchange the last unsorted element with the root of heap */
for (int i = sizeIn - 1; i > 0; i--) {
swap(dataIn[0], dataIn[i]);
heapify(dataIn, 0, i);
}
}