算法描述:为解决选择排序查找最小元的O(N)问题(降低为O(LogN)),将待排序序列构建为最大堆,将其根节点与其最后一个叶子节点交换,交换后除去最后一个叶子节点构建最大堆继续排序。堆排序的动态图示如下所示:
复杂度分析:最坏时间复杂度为O(NlogN),平均时间复杂度也为O(NlogN),效率较高。
主要特点:
- 不稳定;
- 不占用额外内存;
- 但需要构建最大堆,较为麻烦。
C语言描述:
#include<stdio.h>
typedef int ElementType;
void Swap(ElementType *A, ElementType *B) {
ElementType temp = *A;
*A = *B;
*B = temp;
}
/* 将N个元素的数组中以A[root]为根的子堆调整为最大堆 */
void PercDown(ElementType Data[], int root, int N) {
int Parent, Child;
ElementType X = Data[root]; /*取出根结点存放的值*/
for (Parent = root; Parent * 2 + 1 < N; Parent = Child) {
Child = Parent * 2 + 1;
if ((Child != N - 1) && Data[Child] < Data[Child + 1])
Child++; /*Child指向左右子结点的较大者*/
if (X >= Data[Child]) break; /*找到了合适位置*/
else Data[Parent] = Data[Child]; /*下滤X*/
}
Data[Parent] = X;
}
/* 堆排序C语言描述 */
void Heap_Sort(ElementType Data[], int N) {
int i;
for (i = N / 2 - 1; i >= 0; i--) /*建立最大堆*/
PercDown(Data, i, N);
for (i = N - 1; i > 0; i--) {
Swap(&Data[i], &Data[0]); /*删除最大堆顶*/
PercDown(Data, 0, i);
}
}
int main() {
ElementType Data[] = {19, 3, 10, 20, 22, 28, 33, 23, 15, 30};
Heap_Sort(Data, 10);
return 0;
}
附:特殊说明
- 定理:堆排序处理N个不同元素的随机排列的平均比较次数为2NlogN−O(NloglogN);
- 虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序。