文章目录
前言
堆排序,顾名思义是一个利用堆来完成排序的一个操作。在之前,小编在[C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】] 谈到冒泡排序,但是冒泡排序的时间复杂度(O(n^2^))着实有点高,堆排序的时间复杂度相对低很多,O(log~2~N)。
堆排序的实现(升序为例)
堆排序不需要我们手搓一个堆的数据结构,因为我们本质上还是在数组上进行操作
堆排序的思想是:
- 对待排序数组构建一个大堆或者小堆
- 将顶端与末尾进行交换,还剩n-1个数
- 将n-1个数再构建成一个大堆或者小堆,这样反复执行,就可以得到一个有序数组
对于大堆、小堆要有清楚的理解,不知道的可以查看小编博客-->堆的实现(C语言版)
堆排序唯一的坑点是:升序需要建大堆,降序建小堆
结论:升序建大堆,降序建小堆
分析:
假设建小堆:0,3,1,5,4,2,9,7,8,6
虽然把最小的元素取出来了,但是一旦把最小元素拿出来,那么剩下的元素又需要重新建堆,这样时间复杂度会提高,缺陷较大。
假设建大堆:9,8,6,7,3,1,2,4,5,0
第一步:将最大的元素,即堆顶的元素和最后一个元素交换
第二步:除了最大的那一个数,对剩下的数进行向下调整算法,得到堆顶是剩下数中的最大元素,然后再和剩下元素=中的最后一个元素进行交换,依次执行
代码
HeapSort.c
c
# define _CRT_SECURE_NO_WARNINGS
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void AdjustDown(int* arr, int parent, int n)
{
assert(arr);
int child = 2 * parent + 1;
while (child < n)
{
if ((child + 1) < n && arr[child + 1] > arr[child])
{
child++;
}
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void Heapsort(int* arr, int n)
{
assert(arr);
int i = 0;
for (i = (n - 2) / 2; i >= 0; i--) //建堆
{
AdjustDown(arr, i, n);
}
int end = n - 1;
while (end)
{
Swap(&arr[0], &arr[end]);
AdjustDown(arr, 0, end);
end--;
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}