一、基本介绍
堆是一个基于树的特殊数据结构,支持插入、删除、查询最值。它满足每一个子树的根节点一定保存着这棵子树中的最值。大根堆保存的就是最大值,小根堆保存的就是最小值。这里我们只介绍基本的二叉堆的用法。
二、关于二叉堆
二叉堆就是一棵满足“堆性质”的完全二叉树。我们在这里使用数组来存储堆,左子节点的下标就是父节点下标乘以 2 2 2,右子节点的下标就是父节点下标乘以 2 + 1 2+1 2+1.这样的方法可以推广到 k k k叉堆,这里就不细说了。
三、基本操作
1.定义
int heap[maxn],count1;
count1
中保存的是根中的节点数根据完全二叉树的性质,所以count1
同时也是最后一个结点的下标
2.插入
插入的时候,我们直接将要插入的节点放在最后,由void insert(node temp)
实现。然后我们从这个节点开始向上维护堆,由void up(ll son)
实现,让这个节点去到该去的地方,根据大小根堆的不同,调整判断交换的条件。
void up(ll son)
{
while(son>1)
{
if(heap[son].val<heap[son/2].val)
{
swap(heap[son],heap[son/2]);
son>>=1;
}
else
break;
}
}
void insert(node temp)
{
heap[++count1]=temp;
up(count1);
}
3.获得堆顶的值
ll GetTop()
{
return heap[1];
}
4.删除
删除的时候,我们直接将要删除的节点和最后的节点交换,并将count1减1,表示最后一个节点被舍弃,由void Remove()
实现。然后我们从原来的那个节点的位置开始向上向下维护堆,由void up(ll son)
和void down(ll fa)
实现。
void down(ll fa)
{
ll son=fa*2;
while(son<=count1)
{
if(son<count1 && heap[son].val>heap[son+1].val)
son++;
if(heap[son].val<heap[fa].val)
{
swap(heap[son],heap[fa]);
fa=son;
son=fa*2;
}
else
break;
}
}
void Remove(ll p)
{
heap[p]=heap[count1--];
up(p);down(p);
}
四、推荐习题
POJ1456 Supermarket
POJ2442 Sequence
P3620 [APIO/CTSC2007] 数据备份
P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G