堆是一种特殊的完全二叉树。以小根堆为例,这种完全二叉树有一个特点,就是它的父节点都比子节点小。符合这样特点的二叉树,我们也称为最小堆。
反之,如果所有父节点都比子节点要大,这样的完全二叉树称为大根堆,或最大堆。
(若是最小堆,则最小的数在堆顶/树根。)
按一般意义来讲,一个堆的父节点的优先级都比子节点高。
堆有两种基本的写法
1.手写堆
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define leftson (cur<<1)
#define rightson (cur<<1|1)
#define father (cur>>1)
#define int long long
#define MAXN 1000000+10
int n=0,m;
int heap[MAXN];
namespace self
{
#define int long long
void swap(int h[],int x,int y)
{
int t; t=h[x]; h[x]=h[y]; h[y]=t;
return;
}
using namespace self;
void siftdown(int h[],int i)
{
int t;
bool flag=0;
while (i*2<=n && flag==0)
{
if (h[i]>h[i*2])
t=i*2;
else t=i;
if (i*2+1<=n)
{
if(h[t]>h[i*2+1])
t=i*2+1;
}
if (t!=i)
{
swap(heap,t,i);
i=t;
}
else flag=1;
}
return;
}
}
using namespace self;
void down(int cur)
{
int t;
bool flag=0;
while (leftson<=n&&(!flag))
{
if (heap[cur]>heap[leftson])
{
t=leftson;
}
else t=cur;
if (rightson<=n)
{
if (heap[t]<heap[rightson])
{
t=rightson;
}
}
if (t!=cur)
{
swap(heap,t,cur);
cur=t;
}
else flag=1;
}
}
void up(int cur)
{
bool flag=0;
if (cur==1) return;
while (cur!=1&&(!flag))
{
if (heap[cur]<heap[father])
{
swap(heap,cur,father);
}
else flag=1;
cur=father;
}
return;
}
signed main()
{
scanf("%lld",&m);
int q;
while (m--)
{
scanf("%lld",&q);
if (q==1)
{
n++;
scanf("%lld",&heap[n]);
up(n);
continue;
}
if (q==2)
{
printf("%lld\n",heap[1]);
continue;
}
if (q==3)
{
heap[1]=heap[n];
n--;
siftdown(heap,1);
}
}
return 0;
}
无良无分析式玄学代码
2.STL 堆:优先队列
队列是一种先进先出(FIFO)式的数据结构。优先队列与其不同的地方是,优先队列存储的时候,会将(定义的)优先级较大的元素放在较小的元素之前。也就是说优先级最大的元素放在队头。 那么这里就和堆有了共同点:优先级大的放在队前/堆高层。
大根堆的定义:
queue< int >q;
小根堆的定义:
priority_queue< int,vector< int >,greater< int > >q;
一个优先队列的操作:
小根堆基本操作代码
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
int n;
scanf("%d",&n);
int x;
while(n--)
{
scanf("%d",&x);
if (x==1)//命令1 在堆中加入一个数
{
scanf("%d",&x);
q.push(x);
continue;
}
if (x==2)//命令2 输出当前序列中最小数
{
printf("%d\n",q.top());
continue;
}
if (x==3)//命令3 删除当前序列中最小数
q.pop();
}
return 0;
}