堆排序是一种基于二叉堆数据结构的排序算法
二叉树:是 n(n >= 0)个结点的有限集合,该集合或为空集(空二叉树)。或者由一个根节点和两颗互不相交的,分别称为根节点的左子树和右子树的二叉树组成
满二叉树:除了叶子节点,每个结点的度都是2。或者形象来讲,所有叶子节点都排满的二叉树
完全二叉树:节点排序顺序能够完全对应满二叉树的二叉树
既然完全二叉树是依序号排列,那么就可以用一维数组来保存,譬如
1 | 2 | 3 | 4 | 5 | 6 |
[o] | [1] | [2] | [3] | [4] | [5] |
两个重要推论:
1. 对于位置为 k 的节点,其左子节点 = 2 * k +1,右子节点 = 2 * k +2
2. 最后一个非叶子节点的位置 = (n / 2) - 1, n = 数组长度
二叉堆:一个完全二叉树的结构,同时又满足堆的性质(子节点的键值或者索引总是小于或大于其父节点)。根节点总是最大(最大堆)或最小(最小堆)
那么堆排序每次去取其根节点,就能得到最大值或者最小值,剩余节点再调整为二叉堆。如此往复,最终取得的节点就是有序的
以最大堆(升序排列)那么堆排序的流程总结为:
1. 将无序数组构建成 最大堆
2. 交换数组首元素 [0] 与 末尾元素 [arrayLen-1]
3. 数组规模 -1,重新构建最大堆,如此重复
手动演示:
1. 无序数组
35 | 63 | 48 | 9 | 86 | 24 | 53 | 11 |
[0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] |
2. 选择最后一个非叶子节点,开始往上构建最大堆
数组长度 / 2 - 1 = 8 /2 -1 = 3,对应元素为 9[3]
比较 9[3] 的左右子节点,与最大值交换;重复执行交换,最后构建出了最大堆
构建完成后,交换第一个元素与最后一个元素,这样最大值就放到最后
减少数组遍历的长度,继续构建,取出最大值
代码:
交换数组元素
void swap(int *array, int i, int j)
{
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
打印数组,查看运行效果
void dispArray(int *array, int len, const char *desc)
{
int i;
printf("%s", desc);
for(i=0; i<len; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
构建最大堆
void buildMaxHeap(int *array, int len)
{
int i;
int lastNonLeaf = len/2 -1;
for(i=lastNonLeaf; i>=0; i--)
{
ajustMaxHeap(array, len, i);
dispArray(array, len, "Ajust Array:");
}
}
调整最大堆,在根节点,其左右节点之间选择最大值,并且递归调整
void ajustMaxHeap(int *array, int len, int i)
{
int maxIndex = i;
int left = 2*i + 1;
int right = 2*i + 2;
// left child may the max num
if(left < len && array[left] > array[maxIndex])
{
maxIndex = left;
}
// right child is the max num
if(right < len && array[right] > array[maxIndex] && array[right] > array[left])
{
maxIndex = right;
}
if(maxIndex != i) // swap root <> child
{
swap(array, i, maxIndex);
dispArray(array, len, "===swap:");
ajustMaxHeap(array, len, maxIndex); // it may broke ajusted heap, so ajust it
}
}
堆排序主框架,创建最大堆,取最大值,调整最大堆
void heapsort(int *array, int len)
{
int i = len;
buildMaxHeap(array, len);
dispArray(array, len, "MaxHeap Array is:");
// swap root node <> last node; array len--
while(i)
{
swap(array, 0, i-1);
dispArray(array, len, "swap root node, Array is:");
i--;
ajustMaxHeap(array, i, 0);
}
}
主函数,构建测试数组
int main(void)
{
int array[] = {35,63,48,9,86,24,53,11};
int len = sizeof(array) / sizeof(int);
dispArray(array, len, "Orig Array is:");
heapsort(array, len);
dispArray(array, len, "New Array is:");
return 0;
}
测试: