各个函数的功能:
- maxHeapify 的参数为数组 a 和需要操作的下标 i。在调用 maxHeapify 的时候,需要确保根节点为 LEFT(i) 和 RIGHT(i) 的二叉树都是最大堆。若 a[i] 小于其孩子,则让 a[i] 的值在最大堆中逐级下降,从而使得以下标 i 为根节点的子树遵循最大堆的性质。若 a[i] 大于其孩子,那么无需进行任何操作。
- buildMaxHeap 的参数为数组 a 和数组长度 length。不难知道数组 a[length/2, length-1] 中的元素都是树的叶结点,而这些叶结点都可以看作是只包含一个元素的最大堆。这个性质让所有叶结点的父结点都满足了 maxHeapify 函数的使用条件,从而可以让我们自下而上地对树中的其他结点都调用一次 maxHeapify 函数,使得整棵树成为最大堆。
- heapSort 的参数为数组 a 和数组长度 length。首先调用 buildMaxHeap 将数组转换为最大堆,由最大堆的性质可知,根节点的值必然是整棵树的最大值。我们将根节点的值与数组的最后一个元素交换,就可以把最大值放在数组最后面。减少堆中的元素的数量,这时新的根节点有可能不满足最大堆的性质,所以需要调用 maxHeapify 确保整棵树仍然满足最大堆的性质。递归地重复上述过程,一直把新的最大值放到数组最后面,就可以得到一个排序好的数组。
// 堆排序
#include <stdio.h>
#define SWAP(a,b) {a=a^b; b=a^b; a=a^b;}
#define LEFT(i) ((i+1)*2-1)
#define RIGHT(i) ((i+1)*2)
void maxHeapify(int* a, int length, int i);
void buildMaxHeap(int* a, int length);
void heapSort(int* a, int length);
int main(void)
{
int a[] = { 4,1,3,2,16,9,10,14,8,7,18 };
int length = sizeof(a) / sizeof(a[0]);
printf("排序前:");
for (int i = 0; i < length; i++)
printf("%d ", a[i]);
printf("\n");
heapSort(a, length);
printf("排序后:");
for (int i = 0; i < length; i++)
printf("%d ", a[i]);
return 0;
}
void maxHeapify(int* a, int length, int i)
{
int l = LEFT(i);
int r = RIGHT(i);
int largest;
if (l < length && a[l] > a[i])
largest = l;
else
largest = i;
if (r < length && a[r] > a[largest])
largest = r;
if (largest != i)
{
SWAP(a[i], a[largest]);
maxHeapify(a, length, largest);
}
}
void buildMaxHeap(int* a, int length)
{
for (int i = length / 2; i >= 0; i--)
maxHeapify(a, length, i);
}
void heapSort(int* a, int length)
{
buildMaxHeap(a, length);
for (int i = length - 1; i > 0; i--)
{
SWAP(a[0], a[i]);
maxHeapify(a, --length, 0);
}
}