学习堆排序前,最好先看看二叉堆的概念:https://blog.csdn.net/qq_36748278/article/details/81867582
以最小堆为例:最小堆的堆顶元素是最小的
使用额外数组方式:
- 因为我们知道
堆顶元素是最小
的; - 我们依次把堆顶元素删除,并且用当前堆的最后一个元素放在堆顶;
- 并且把删除的元素放在一个辅助temp数组里,
每次删除堆顶元素
(删除的即是从小到大排序的)后,重建当前堆,即堆顶元素下沉,以保证二叉堆的特性,这样堆顶又是最小的- 这样的话,temp数组中的元素就是从小到大排列的
不使用额外数组的方式:
- 也可以不使用额外的temp数组,直接把删除的元素存放到堆的末尾,
- 即堆顶元素和当前堆最后一个元素进行交换,被交换到堆尾的元素看做是被删除的
- 这样的话,经过n - 1 次删除之后,数组就是一个有序数组了
可以看看下面的例子:
依次进行,直到堆中所有元素删除
看如下代码使用:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
// 下沉:即把当前节点和孩子节点进行比较
void DownAdjust(int * a , int parent , int indexSize)
{
int temp = a[parent];
// 左孩子节点先赋值
int child = 2 * parent + 1; // 找到左右节点中的最小值
// 下沉要一直下沉,直到叶子节点
while(child < indexSize)
{
// 如果存在右节点,找出左右节点中最小的那个进行交换
if ((child + 1 < indexSize) && (a[child] > a[child + 1]))
{
child = child + 1;
}
// 当父节点比子节点都小或者相等时,下沉结束
if(temp <= a[child])
{
break;
}
// 单向赋值(为啥不是)
a[parent] = a[child];
parent = child;
child = 2 * parent + 1;
}
a[parent] = temp;
}
void PrintArr(int * a , int size)
{
for(int i = 0 ; i < 10; ++i)
{
printf("%d " , a[i]);
}
printf("\n");
}
void HeapSort(int * a , int indexSize)
{
// 堆顶元素删除---最后一个元素放到堆顶---重建堆-------堆顶元素放在二叉堆最后一个节点
// 即堆顶元素和最后一个元素交换------重建堆(堆顶元素下沉)
while ( indexSize >= 0) // indexSize: 即从最后一个元素开始,依次递减
{
int temp = a[0];
a[0] = a[indexSize];
a[indexSize] = temp;
DownAdjust(a , 0 , indexSize);
indexSize--;
}
}
int main()
{
int a[10] = {0 , 3, 1 , 5 , 4 , 8 , 2 , 6 , 9 , 7};
PrintArr(a , 10);
HeapSort(a , 9);
PrintArr(a , 10);
return 0;
}
输出结果:
0 3 1 5 4 8 2 6 9 7
9 8 7 6 5 4 3 2 1 0