堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或者等于其左右孩子结点的值,称为小顶堆。
堆数组:把大顶堆或小顶堆用层序遍历存入数组。
堆排序就是利用对(假设利用大顶堆)进行排序的方法。它的基本思想是,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列。
步骤:1、如何由一个无序序列构建一个堆;2、如何在输出堆顶元素后,调整剩余元素成为一个新的堆。
void HeapSort(SqList *L)
{
int i;
for (i = L->length / 2; i > 0; i--)
HeapAdjust(L, i, L->length);
for (i = L->length; i > 1; i--)
{
swap(L, 1, i);
HeapAdjust(L, 1, i - 1);
}
}
void HeapAdjust(SqList *L, int s, int m)
{
int temp, j;
temp = L->r[s];
for (j = 2 * s; j <= m; j *= 2)
{
if (j < m && L->r[j] < L->r[j + 1])
j++;
if (temp >= L->r[j])
break;
L->r[s] = L->r[j];
s = j;
}
L->r[j] = temp;
}
由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlogn)。
不过由于记录的比较和交换是跳跃式进行,因此堆排序也是一种不稳定的排序方法。