堆排序
基本思想:
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是
排升序要建大堆,排降序建小堆 ,利用堆删除的思想进行排序
向下调整: 条件---->在调整某个节点时,必须保证该节点的左右子树已经满足堆的性质
void AdjustDown(int array[] , int size, int parent)
{
// 用child标记parent较大的孩子,parent可能有左没有右孩子
int child = parent * 2 + 1;
while (child < size)
1.如果右孩子存在的情况下,找较小的孩子,并用child进行标记
2.检测parent是否满足堆的性质,与child的大小关系
if (array[child] > array[parent])
小:需要将双亲与孩子节点中的元素进行交换,为了防止调整后子树堆的性质被破坏掉,然 后继续向下调整
parent = child; child = parent * 2 + 1;
大:parent节点已经满足大堆的特性------>直接返回
}
堆删除:每次删除堆顶元素
Ⅰ.检测堆是否为空,堆为空直接返回,否则进行Ⅱ
Ⅱ.将堆顶元素与堆中最后一个元素进行交换,将堆中有效元素个数减1 对堆顶元素进行向下调整
void Swap(int* left, int* right)
{
int temp = *left;
*left = *right;
*right = temp;
}
// 建堆,向下调整法
void HeapAdjust(int array[], int size, int parent)
{
// 用child标记parent较大的孩子,默认先标记parent的左孩子
// 先标记左孩子的原因是:如果parent有孩子,parent一定是先有左孩子,然后才有右孩子
int child = parent * 2 + 1;
while (child < size)
{
// 找parent中较大的孩子:用parent左右孩子比较
// 必须先保证parent的右孩子存在
if (child+1 < size && array[child + 1] > array[child])
child += 1;
// 检测parent是否满足大堆的性质
if (array[child] > array[parent])
{
Swap(&array[child], &array[parent]);
// 交换后可能导致子树不满足堆的性质,所以需要继续向下进行
parent = child;
child = parent * 2 + 1;
}
else
{
return;
}
}
}
// 堆排序(选择排序的一种)
// 时间复杂度:O(NlogN)
// 空间复杂度:O(1)
// 稳定性:不稳定
void HeapSort(int array[], int size)
{
int end = size - 1;
// 1. 建堆
// 注意从倒数第一个非叶子节点的位置开始使用堆调整,一直减减,调整到根节点的位置
for (int root = (size - 2) / 2; root >= 0; root--)
HeapAdjust(array, size, root); // 向下调整---时间复杂度:O(logN)
// 2. 排序--->利用堆删除的思想进行排序
while (end)
{
Swap(&array[0], &array[end]);
HeapAdjust(array, end, 0);
end--;
}
}
堆排序的特性总结:
1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定