注:可以不用管这个想到哪儿写到哪儿的看不懂的思想和从《啊哈!算法》上抄的算法模板,只要暂时会用priority_queue就好了。
思想
堆是优先队列的实现。
一种完全二叉树。
对于最大堆,父节点的值都比子节点大;对于最小堆,父节点的值都比子节点小。
用一个数组来存树。
新增一个数,放在末尾,判断是否要进行上升操作。
将最小的数删除,将一个新的数放在堆顶,判断是否进行下沉操作。
通过这个进行堆排序,可扩展为求n个数中前k个大(小)的数,即建一个大小为k的堆进行维护。
代码
#include<bits/stdc++.h>
using namespace std;
//从大到小排序,如果从小到大,则向下调整时应记录较大结点的编号,即建立一个最大堆
int h[101];//存放堆
int n;//堆的大小
//堆下沉
void siftdown(int i)//传入一个需要向下调成的结点编号
{
int t,flag=0;//标记是否需要继续调整
//当i结点有儿子,并需要继续调整的时候执行
while(i*2<=n && flag==0)
{
if(h[i]>h[i*2])
t=i*2;
else
t=i;//判断其与左儿子的关系,t记录较小结点的编号
if(i*2+1<=n)//判断是否有右儿子
if(h[t]>h[i*2+1])
t=i*2+1 ;
if(t!=i)//如果最小结点不是自己,说明子节点中有比父节点更小的数
{
swap(h[t],h[i]);//交换他们
i=t;//更新i为刚刚交换的子节点编号,便于接下来的向下调整
}
else
flag=1;
}
return;
}
//建堆
void creat()
{
int i;
//从最后一个非叶节点到第1个结点依次向下调整
for(i=n/2;i>=1;i--)
siftdown(i);
return;
}
//堆排序
void heapsort()
{
while(n>1)
{
swap(h[1],h[n]);
n--;
siftdown(1);
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int i,num;
cin>>num;
for(i=1;i<=num;i++)
cin>>h[i];
n=num;
creat();
heapsort();
for(i=1;i<=num;i++)
cout<<h[i]<<" ";
return 0;
}