一:前言
在[C/C++]数据结构 堆的详解中,介绍了什么是堆,并且完成了堆的实现和一系列接口,包括向上调整法和向下调整法等,接下来小编介绍一个有点量级的排序方法------堆排序,时间复杂度为O(n*lgn)
二:堆排序详解
2.1 方法介绍
1.首先将待排序数组建为大堆,此时堆顶元素就为数组最大值了
2.交换堆顶和堆尾元素,此时最大元素就到了堆尾,目前数组最大元素就排好了,现在就假设堆里没有当前这个最大元素了,堆头下面的左右子树仍然是大堆,只需要再将堆顶元素向下调整到合适位置,剩下的n-1个元素还是大堆
3.堆头堆尾交换,向下调整,如此反复就可排序
ps.排序以升序为例,升序建大堆,降序建小堆
那么怎么将待排序数组建为大堆呢?
假设数组第一个元素是堆,再把第二个元素插入,向上调整为堆,插入第三个元素时,前两个是堆,向上调整,插入第四个元素时,前三个元素是堆,以此反复就可以把所有元素建为堆
//建堆
for (int i = 1; i < size; i++)
{
AdjustUp(a, i);
}
2.2 排序
假设我们的待排序数组为:
建好大堆以后就可以开始排序了
过程如下:
处理最大元素:
先将堆头元素和堆尾元素交换
忽略9,将1向下调整到合适位置
处理次大元素:
再次堆头堆尾交换
忽略8和9,将1向下调整到合适位置
处理第三大元素:
堆头堆尾交换
忽略6和8和9,将2向下调整到合适位置
处理第N大元素:
........................
其实堆排序的实质就是选择排序,每次可以选出一个最大数,放在堆尾,再去处理前n-1个数
代码实现:
#include<stdio.h>
typedef int HeapDataType;
void swap(HeapDataType* a, HeapDataType* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//大堆
void AdjustUp(HeapDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child>0)
{
if (a[parent] < a[child])
{
swap(&a[parent], &a[child]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//大堆
void AdjustDown(HeapDataType* a, int size, int parent)
{
int child = parent * 2 + 1;
while (child<size)
{
//找较大的孩子
if (a[child + 1] > a[child] && child+1<size)
{
child = child + 1;
}
if (a[parent] < a[child])
{
swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(HeapDataType* a, int size)
{
//建堆
for (int i = 1; i < size; i++)
{
AdjustUp(a, i);
}
//排序:升序
int end = size - 1;
while (end>0)
{
swap(&a[0], &a[end]);
AdjustDown(a, end, 0); //end指最后一个元素,同时end的值为前面元素的个数
end--;
}
}
测试:
int main()
{
int a[] = { 9,8,6,5,4,2,2,1 };
HeapSort(a, sizeof(a) / sizeof(a[0]));
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
return 0;
}