堆排序
堆排序的前身–选择排序
void Selection_Sort(ElementType[] A, int N) {
for (int i = 0; i < N; i++) {
// 从A[i]到A{N-1}中找到最小元,并将其位置赋给MinPosition
MinPosition = ScanForMin(A, i, N - 1);
// 将未排序部分的最小元换到有序部分的最后位置
Swap(A[i], A[MinPosition]);
}
}
时间复杂度: T=Θ(N2)
堆排序的实现
以下两种算法实现的堆排序都是不稳定的
算法1
- 根据指定数组建立最小堆
- 从最小堆中删除最小元素并保存起来
- 把之前保存的元素赋给原数组
void Heap_Sort(ElementType[] A, int N) {
BuildMinHeap(A); // 时间复杂度:O(N)
for (i = 0; i < N; i++)
Temp[i] = DeleteMin(A); // 时间复杂度:O(logN)
for (i = 0; i < N; i++) // 时间复杂度:O(N)
A[i] = Temp[i];
}
- 时间复杂度: T(N)=O(NlogN)
- 需要额外的 O(N) 空间,并且复制元素需要时间
算法2
- 根据指定数组建立最大堆
- 将最大堆的最大元素(即数组的首元素)与数组的最末元素交换,并缩小最大堆的规模和调整最大堆
- 重复2,直到 N−1 次
void Heap_Sort(ElementType[] A, int N) {
for (i = N/2 - 1; i >= 0; i--) // 建立最大堆
PercDown(A, i, N); // 调整最大堆
for (i = N - 1; i > 0; i--) {
Swap(A[0], A[i]); // 相当于删去最大堆的顶上元素
PercDown(A, 0, i); // 调整最大堆
}
}
- 定理:堆排序处理N个不同元素的随机排列的平均比较次数是 2N logN−O(Nlog logN)
- 时间复杂度: T(N)=O(NlogN)
- 虽然堆排序给出最佳平均时间复杂度,但实际效果不如用Sedgewick增量序列的希尔排序