前言
冒泡排序具有很强的局限性,在具体使用的时候并不方便
例如:冒泡排序的时间复杂度为O(N^2),也就代表着100w的数据,如果用冒泡排序的话,需要进行1w亿次
为了提高排序的速度,我们可以采用堆排序
一、堆排序的思路
利用堆的性质
大堆:每个结点的值都大于或等于其左右孩子结点的值
小堆 :每个结点的值都小于或等于其左右孩子结点的值
将堆顶的元素保留起来,放在合理的位置
只要堆始终被维护这,那我们就一直可以获得堆中的最值
依次来进行排序
堆排序的时间复杂度为O(N*logN)
二、使用方法
1.利用现有的堆保存堆顶的数据
代码如下(示例):
void HeapSort(int* a, int n)
{
//在有现成的堆的情况
//把数组导入堆中去
//把pop堆顶出来的元素存到a里面
HeapInit(&hp);
for (int i = 0; i < n; i++)
{
//插入元素
HeapPush(&hp, a[i]);
}
//将堆里面的数据再重新拷贝回数组中
for (int i = 0; i < n; i++)
{
a[i] = HeapTop(&hp);
HeapPop(&hp);
}
//以下是建堆时需要的自定义函数
//堆的初始化
void HeapInit(Heap* hp)
{
hp->_capacity = 4;
hp->_size = 0;
HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * 4);
if (!tmp)
{
perror("malloc");
return;
}
hp->_a = tmp;
}
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
assert(hp);
AdjustCapacity(hp);
//第一步插入
hp->_a[hp->_size] = x;
hp->_size++;
//第二步调整
AdjustUp(hp->_a, hp->_size - 1);
}
// 堆的删除
void HeapPop(Heap* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
//交换首尾
Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
hp->_size--;
//调整
AdjustDown(hp->_a, hp->_size, 0);
}
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
assert(hp);
if (HeapEmpty(hp))
{
return -1;
}
return hp->_a[0];
}
2.把原有的数组调整为堆,将top元素放数组尾
代码如下(示例):
void HeapSort(int* a, int n)
{
//当要调整的元素只剩一个时,就意味着调整完了
while (n != 1)
{
//从最后一个叶子节点的父节点开始依次向下调整
//调整顺序不断向上
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(a, n, i);
}
Swap(&a[0], &a[n - 1]);
n--;
}
}
//以下是需要使用到的自定义函数
//交换两个元素
void Swap(HPDataType* a, HPDataType* b)
{
HPDataType tmp = *a;
*a = *b;
*b = tmp;
}
//向下调整
void AdjustDown(int *a, int n, int parent)
{
assert(a);
int child = parent * 2 + 1;
while (child < n)
{
if (a[child] > a[child + 1] && child + 1 < n)
{
child++;
}
if (a[child] < a[parent])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
总结
以上就是今天要讲的堆排序的内容,本文仅仅简单介绍了堆排序的使用,能够有效的解决排序速度慢的问题。