堆排序
堆排序是一种时间复杂度为 O(N log N) 的常见排序方法。学习堆排序前,先讲解数据结构中的二叉堆。
二叉堆的定义
二叉堆是完全二叉树或者是近似完全二叉树。
二叉堆满足两个特性:
- 父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
- 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:

由于其它几种堆(二项式堆、斐波纳契堆等)用得较少,一般将二叉堆就简称为堆。
堆的存储
一般都用数组来表示堆,i 结点的父结点下标就为 (i - 1) / 2。它的左右子结点下标分别为 2 * i + 1 和 2 * i + 2。如第 0 个结点左右子结点下标分别为 1 和 2。

堆的操作——插入删除
下面先给出《数据结构 C++ 语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。

堆的插入
每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中,对照不难写出插入一个新数据时堆的调整代码:
// 新加入 i 结点 其父结点为 (i - 1) / 2
void MinHeapFixup(int a[], int i)
{
int j, temp;
temp = a[i];
j = (i - 1) / 2; // 父结点
while (j >= 0 && i != 0)
{
if (a[j] <= temp)
break;
a[i] = a[j]; // 把较大的子结点往下移动,替换它的子结点
i = j;
j = (i - ) / ;
}
a[i] = temp;
}



