推排序(手写堆)
堆:一个完全二叉树(上层是满的,最后一层从左向右依次排列)
大根堆:每个点都大于等于他的左右儿子,根节点是集合里的最大值
小根堆:每个点都小于等于他的左右儿子,根节点是集合中的最小值
手写堆需要维护的操作:
1.插入一个数(插到数组最后一位然后再调整)
2.求集合中的最小值(头节点)
3.删除一个数(删除后用尾结点填充,再调整)
4.删除一个任意元素( 4 和 5在STL库中的堆结构实现不了 )
5.修改一个任意元素

手写堆的两个基本操作:
down操作:从根开始,若不符合堆的概念,则进行换位,不断递归直到符合堆
up操作:
以这两个基本操作可以完成维护堆的五个操作
手写堆的实现方式:一维数组
数组的第一个元素表示根节点(下标从1开始)。x的左儿子下标为 2x,右儿子下标为2x+1
例题:

输入样例:
5 3 4 5 1 3 2
预期输出:
1 2 3
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int h[N],size;
int n,m;
void down(int u)
{
int t = u;//t表示根节点和他的两个儿子之间最小的索引值
if(u*2<=size &&h[u*2]<h[t]) t=u*2;
if(u*2+1<=size&& h[u*2+1]<h[t]) t=u*2+1;
if(u!=t)
{
swap(h[u],h[t]);
down(t);
}
}
/**
up操作,本题中用不到
void up(int u)
{
while(u/2 && h[u] < h[u/2])
{
swap(h[u),h[u/2)];
u=u/2;
}
}
**/
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>h[i];
size =n;
//建堆,时间复杂度O(n)
for(int i=n/2;i>0;i--) down(i);
//输出最小值
while(m--)
{
printf("%d ",h[1]);
h[1]=h[size];
size --;
down(1);
}
}

浙公网安备 33010602011771号