假如有 14 个数分别是 99、5、36、7、22、17、46、12、2、19、25、28、1 和 92。现在我们需要删除其中最小的数,并增加一个新数 23,再次求这 14 个数中最小的一个数。
首先我们先把这个 14 个数按照最小堆的要求(就是所有父结点都比子结点要小)放入一棵完全二叉树,就像下面这棵树一样。
很显然最小的数就在堆顶,假设存储这个堆的数组叫做h的话,最小数就是 h[ 1]。接下来,我们将堆顶的数删除,并将新增加的数 23 放到堆顶。显然加了新数后已经不符合最小堆的特性,我们需要将新增加的数调整到合适的位置。那如何调整呢?
向下调整!我们需要将这个数与它的两个儿子 2 和 5 比较,并选择较小一个与它交换,交换之后如下。
我们发现此时还是不符合最小堆的特性,因此还需要继续向下调整。于是继续将 23 与它的两个儿子 12 和7比较,并选择较小一个交换,交换之后如下。
|
到此,还是不符合最小堆的特性,仍需要继续向下调整直到符合最小堆的特性为止。
我们发现现在已经符合最小堆的特性了。综上所述,当新增加一个数被放置到堆顶时,如果此时不符合最小堆的特性,则将需要将这个数向下调整,直到找到合适的位置为止,使其重新符合最小堆的特性。
堆排序方法一:从小到大排序,先建立最小堆,然后每次删除顶部元素并将顶部元素输出或者放入一个新的数组中,直到堆为空为止。
#include<iostream>
using namespace std;
int n;
int h[101];
//建立最小堆
void siftdown(int i)
{
int t; //存储较小的结点的编号
int flag=0; //标记是否需要调整顺序
//判断是否存在左孩子以及是否需要调整
while(i*2<=n && flag==0)
{
//如果父结点大于左孩子,则交换
if(h[i]>h[2*i])
{
t=2*i;
}
else
t=i;
//判断是否存在右孩子
if(i*2+1<=n)
{
//如果此时的父结点大于右孩子,则交换
if(h[t]>h[2*i+1])
{
t=2*i+1;
}
}
if(t!=i)
{
//注意调用swap函数传入的参数
swap(h[t],h[i]);
i=t; // 更新i为刚才与它交换的孩子结点的编号
}
else
{
flag=1; //flag=1说明不需要调整序列,跳出循环
}
}
return;
}
//创建堆
void creat()
{
for(int i=n/2;i>=1;i--)
{
siftdown(i);
}
return;
}
//去除最小堆的根节点,即输出最小的数
int deletemin()
{
int t;
t=h[1];
h[1]=h[n];
n--;
siftdown(1);
return t;
}
int main()
{
int num;
cin>>num;
for(int i=1;i<=num;i++)
{
cin>>h[i];
}
n=num;
creat();
for(int i=1;i<=num;i++)
{
cout<<deletemin()<<" ";
}
return 0;
}
堆排序方法二:从小到大排序,建立最大堆,在最大堆建好后,最大元素在h[1],因为是从小到大排序,所以将h[1]与h[n]交换,此时h[n]为最大的元素。交换后需要将h[1]向下调整保持堆的特性。反复执行,直到堆的大小为1.
#include<iostream>
using namespace std;
int n;
int h[101];
//建立最大堆
void siftdown(int i)
{
int t;
int flag=0; //标记是否需要调整
while(i*2<=n && flag==0)
{
if(h[i]<h[2*i])
{
t=2*i;
}
else
t=i;
if(i*2+1<=n)
{
if(h[t]<h[2*i+1])
{
t=2*i+1;
}
}
if(t!=i)
{
//注意调用swap函数传入的参数
swap(h[t],h[i]);
i=t;
}
else
{
flag=1;
}
}
return;
}
//堆排序(注意使用此方法输出递增序列,必须是建立最大堆)
void heapsort()
{
while(n>1)
{
swap(h[1],h[n]);
n--;
siftdown(1);
}
return;
}
void creat()
{
for(int i=n/2;i>=1;i--)
{
siftdown(i);
}
return;
}
int main()
{
int num;
cin>>num;
for(int i=1;i<=num;i++)
{
cin>>h[i];
}
n=num;
creat();
heapsort();
for(int i=1;i<=num;i++)
{
cout<<h[i]<<" ";
}
return 0;
}
从小到大进行排序