AcWing 838. 堆排序
原题链接
简单
作者:
满目星河_0
,
2021-03-31 12:30:10
,
所有人可见
,
阅读 161
带注释(超详细)
//算法思想:用一个数组实现堆,利用down操作实现小根堆的创建。
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int h[N];//用来实现堆的数组
int cnt; //表示堆的最后一个节点
void down(int u){
int t=u; //用t来存储当前二叉树中下标最小的节点
if(2*u<=cnt && h[2*u]<h[t]) t=u*2; //左儿子更小
if((2*u+1)<=cnt && h[2*u+1]<h[t]) t=u*2+1; //右儿子更小
if(u!=t){ //u不是最小的那个节点就交换
swap(h[u],h[t]);
down(t); //递归到当前节点
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
cnt=n;
for(int i=n/2;i>=1;i--) down(i);
//根据完全二叉树的性质,从n/2开始down就行了,先把下面的节点down好,再down上面的。
//为什么不能从根节点开始down?
//进行down(i)时需要保证i的左右两个儿子都已经满足堆的性质。从n / 2开始向前做,相
//当于从整棵二叉树的最后一层开始往上做,那么是可以保证这个性质的。但是如果从根
//节点向下做,则第一次就不满足这个性质了
while(m--){
//输出根节点并覆盖根节点。
printf("%d ",h[1]);
h[1]=h[cnt--];
down(1);
}
return 0;
}