简介堆
堆是一种数据结构,是一棵二叉树(尽量地满足完全二叉树的规律)。他有一个特点,就是两个儿子的值均大于或小于父节点。那么这个堆就被称为大顶堆或小顶堆。同一级的元素不比较大小,它可以用到优先队列之中,还有其他很神奇的应用。
操作
I.维护队的性质
其实就是一个步骤:如果它不满足堆的性质,那么就继续维护,否则结束。
1.向上维护
如果节点x与它的父亲x/2的关系不合法,则x与x/2交换。
void up(LL x)
{
LL p=x;
while (p>1 && d[p/2]<d[p])swap(d[p],d[p/2]),p/=2;
}
2.向下维护
如果节点x与它的儿子的关系不合法,则比较左儿子和右二子的大小,较大(或较小)的那个和x交换。
void down(LL x)
{
LL l=x*2,r=x*2+1;
while (l<=tot && d[x]<=d[l] || (r<=tot) && d[x]<=d[r])
{
LL mx=l;
if (r<=tot && d[r]>d[l]) mx=r;//比较大小
swap(d[x],d[mx]);x=mx;
l=x*2,r=x*2+1;
}
}
II.建立堆
首先我们要将一个数组转化成一个堆。那么我们对于数组中的每一个元素,都要维护堆的性质。
void build()
{
for(int i=tot/2;i>=1;i--) down(i);
//其中tot表示这个数组的元素个数。
}
III.删除堆顶的元素
当我们要取最优值的时候,我们要将堆顶的元素删掉,然后最后一个元素到堆顶,维护堆。
void del(LL x)
{
if (d[tot]<d[x])
{
memcpy(d[x],d[tot],sizeof(d[x]));tot--;
down(x);
} else
{
memcpy(d[x],d[tot],sizeof(d[x]));tot--;
up(x);
}
}
PS:删除操作可以应用到优先队列之中
IV.插入操作
向堆中添加一个元素到堆末,然后向上维护堆。
void ins(LL x)
{
d[++tot]=x;
up(tot);
}
总结
堆时间复杂度:
O(nlogn)
堆多应用于优先队列或者是堆排序。
堆是一个重要的数据结构,在很多题目中容易遇到。