堆排序的基本过程:
1. 找到最大的元素,放到最后面去
2. 找到第二大的元素,放在倒数第二个位置
。。。依次类推,直到所有元素完成排序。
其中每一步中,找最大元素的方法是借助堆。堆可以看成是一个完全二叉树,且每个节点的值都大于它的子节点的值。对于数组来说,就是任意第[i]个元素大于第[2i+1]和第[2i+2]个元素。为了将无序数组变成堆,需要从叶到根依次建堆。也就是从 从后往前第一个有子节点的节点 开始,到根节点为止,依次建堆。之所以选择这个顺序,是因为这样可以保证对每一个节点建堆的时候它的左右子树已经是堆了。完成第一次建堆后,首个元素为最大值,将其与最后一个元素互换完成整个排序的第一步。
此时数组中最后一个元素是最大值,前n-1个元素中,根节点的左右子树都是堆,只有根元素不满足堆的条件。只需对根节点在执行一次调整最大堆的过程,前n-1个元素将又建成一个堆,第二大的元素位于根。与倒数第二个元素交换,完成整个过程的第二步。
依次类推,完成整个排序过程。
// Adjust heap for array that begin at array, and length = nLen.
// The left subtree and right subtree are already heap.
void MaxHeapify(int array[], size_t nLen)
{
int idxLarge = 0;
int nTemp = array[0];
for (int i=0; 2*i+1<nLen; i=idxLarge)
{
int idxLeft = 2*i+1;
int idxRight = idxLeft+1;
if (array[idxLeft]>nTemp)
idxLarge = idxLeft;
if (idxRight < nLen && array[idxRight]>array[idxLarge])
idxLarge = idxRight;
if (idxLarge != i)
array[i] = array[idxLarge];
else
break;
}
array[idxLarge] = nTemp;
}
void HeapSort(int array[], size_t nLength)
{
// BuildMaxHeap
for (int idx=nLength/2 - 1; idx>=0; idx--)
{
MaxHeapify(array+idx, nLength-idx);
}
// swap root of heap with the last element, and re-adjust heap.
for (int i=nLength-1; i>=1; i--)
{
int nTemp = array[0];
array[0] = array[i];
array[i] = nTemp;
MaxHeapify(array, i);
}
}