#include <stdio.h> //关于最小堆,我们关心的是更小的那个节点
int h[101]; //用于存储数组
int n; //用于存储堆的大小
void swap(int x, int y)
{
int temp;
temp = h[x];
h[x] = h[y];
h[y] = temp;
}
void sift_down(int i) //传入需要向下调整的编号,然后按照最小堆,向下调整
{
int t, flag = 0; //t用于存储,flag用于记录是否需要继续调整
while (i * 2 <= n && flag == 0)
{
if (h[i] > h[i * 2]) //首先判断左节点,并用t记录较小节点的编号
t = i * 2;
else
t = i;
if (i * 2 + 1 <= n) //如果当前结点存在右儿子,再对右儿子进行讨论
if (h[t] > h[i * 2 + 1]) //如果右儿子更小,更新较小结点的编号
t = i * 2 + 1;
if (t != i) //如果最小节点的编号不是自身,意味着子节点中有比父节点更小的
{
swap(t, i); //交换他们,为了构建新的最小堆
i = t; //更新i为刚才于其交换的儿子的编号,便于接下来的向下调整
}
else
flag = 1; //否则说明父节点已经比两个子节点都小, 不需要再进行调整了
}
}
void sift_up(int i) // 传入一个需要向上调整的节点的编号
{
int flag = 0; //用来标记结点是否需要向上调整
if (i == 1) return; //如果是堆顶,就返回,不需要再调整
while (i != 1) //不是堆顶且当前结点的值小于父节点就向上调整 (向上调整的函数,对于对的判断刚好与向上调整相反)
{
if (h[i] < h[i / 2]) //判断是否比父节点小
swap(i, i / 2); //与父结点交换,向上调整
else
flag = 1; //表明当前节点的值小于父节点,不需要再调整了
i = i / 2;//!!!更新编号,进而继续向上调整
}
}
void creat() //创建堆
{
for (int i = n / 2; i >= 1; i--) //从最后一个非叶节点开始,进行调整,当全部调整完了时,堆就构造好了
sift_down(i);
}
int delete_min() //删除堆中最小的元素,也就是根节点,再重新调整最小堆
{
int t = h[1]; //记录最小值,该值接下来要被覆盖,进而进行堆的调整
h[1] = h[n--]; //将堆的最后一的元素赋值到堆顶,进而使堆的尺寸减1
sift_down(1); //向下调整,构造新堆
return t;
}
int main()
{
int num;
scanf("%d", &num);
for (int i = 1; i <= num; i++)
scanf("%d", &h[i]);
n = num;
creat();
for (int i = 1; i < num; i++) // 每次将最小值删除并且打印, 实现堆排序。
printf("%d ", delete_min());
return 0;
}
参考于啊哈算法。