前言
每个排序方法的速度都有各异,其中,堆排序算是顶流,速度相当的快,但也相对难理解点,这篇文章将想你讲解从堆的建立到堆排序
一、堆是什么?
堆就是一种特殊的队列
堆是由二叉树延伸出来的,而二叉树又是从顺序表(数组)转化过来的
数组本来就是数组,但是有大佬把数组想象成了二叉树,然后又接着在二叉树的基础上搞出了堆,堆就可以衍生出很多技巧和方法
二、建堆方法
1.向上建堆法
向上建堆法原理就是将要导入的数组依次插入到新的数组中,但是每插入一次都顺便向上调整一次
图解如下:
示例代码:
void UpAdjust(int* arr, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
2.向下建堆法
向下建堆的原理就是可以将某棵已经建的差不多的树(只剩堆顶没调整)建成完整的堆,前提是这棵树下面就是堆(适合原地建堆)
图解如下:
示例代码:
//向下调整
void DownAdjust(int* arr, int size, int parent) //size为
{
int child = parent * 2 + 1;
while (child < size)
{
//找出两个孩子中最小的
if (child + 1 < size && arr[child + 1] > arr[child])
{
child++;
}
if (arr[parent] < arr[child])
{
Swap(&arr[parent], &arr[child]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}
}
三、堆排序的方法
(建大堆为升序,建小堆为降序)
(前提是得先有堆)
换位法:
- 将堆顶的数都放在最后面,已经放了的就不用管了
- 一开始size个元素的堆,将堆顶元素和最后一个元素交换(最后一个元素不用再参与调整),然后这size-1个元素再调整出新的堆(向上或者向下建堆法都可以),再把堆顶元素和最后一个元素交换,直到size = 1;
- 利用堆顶的元素为最值这一特点,将最值依次放到队尾,便达到了排序的作用
图解如下:
示例代码:
//堆排序
void HeapSort(int* arr, int size)
{
assert(arr);
assert(size != 0);
//先建一次堆
for (int i = 1; i < size; i++)
{
UpAdjust(arr, i);
}
//此时已经有最大的数了
//利用向下调整法,将之后次大的数放到最后面
while (size > 1)
{
//size就是数组的个数
Swap(&arr[0], &arr[size - 1]);//arr[size - 1]就是数组最后一个元素
//当最大的那个数已经被放到最后面的时候,要调整的个数就变成了size-1
DownAdjust(arr, size - 1, 0);//向下调整中的size-1代表的是,你要调整的数据个数,并不是数组最后一个下标
size--;
}
}
总结
以上就是今天要讲的内容,本篇文章着重讲解了两个建堆方法以及堆排序的原理和思路,在力扣以及牛客网中还会有很多类似的题目,今后将会持续更新,敬请关注!