如何手写一个堆?
我们对堆主要有如下操作:
一.插入一个数
我们首先把要插入的数x插入到堆的末尾,再根据其值大小进行是否up()操作:
heap[++size]=x; up(size);
二.求集合当中的最小值
对小堆而言,堆顶元素就是最小值
heap[1]
三.删除最小值
因为是用一维数组模拟堆,数组开头元素是最难删除的,需要后面的元素一阶一阶向前覆盖。最组尾元素是最容易删除的,只有size--就可以了。
因此我们只要把堆尾的元素覆盖给堆顶元素,然后再把堆尾元素删除了,最后再对堆顶元素进行down()操作
heap[1]=heap[size];
size--;
down(1);
四.删除任一元素
对于任一元素x我们先找到它,然后用堆尾元素覆盖x,再把堆尾元素减去,再根据heap[x]的值进行up()或down()操作
heap[k]=heap[size]
size--;
down()||up();
五.修改任一元素
对于任一元素x,我们先找到它,然后将其修改,修改完之后再根据其修改后的值的大小进行up()或down()操作
heap[k]=x;
down()||up()
模板题
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int h[N],sz;
void down(int u)
{
int t=u; //我们用t来存最小值的下标
if(u*2<=sz&&h[u*2]<h[t])t=u*2;
if(u*2+1<=sz&&h[u*2+1]<h[t])t=u*2+1;
if(t!=u) //说明u不是最小值
{
swap(h[u],h[t]);
down(t);
}
}
void up(int u)
{
while(u/2&&h[u/2]>h[u]){ //当父节点大于u节点的时候
swap(h[u/2],h[u]); //就把较大的父节点换下来,把较小的u节点送上去
u/=2; //继续向上找父亲节点
}
}
signed main()
{
int n,m;cin>>n>>m;
sz=n;
for (int i = 1; i <= n; i++)
scanf("%d", &h[i]);
for (int i = n / 2; i; i--)
down(i);
while(m--)
{
printf("%d ",h[1]);
h[1]=h[sz];
sz--;
down(1);
}
return 0;
}