浅谈堆

堆是一种支持插入,查询最值以及删除最值的数据结构。

堆是一棵二叉树,这棵二叉树所有的叶子都集中在最下面两层,并且如果一个点有右儿子的话一定有左儿子,而且最下面的叶子全部都靠在左边。由于这个性质,我们可以很快找到一个点\(p\)的父亲\(p>>1\)和左右儿子\(p<<1\)以及\(p<<1|1\)

堆满足任意一个结点的权值都小于/大于父亲结点的权值的性质,我们称这个性质为堆性质。那么显然,堆顶就是最值所在。

插入

在最下层新建一个叶子结点,权值为插入的数值。为了满足堆性质,不断上浮去维护,直到这个点满足堆性质了才停下来。以小根堆为例:

代码如下:

void ins(int x) {
    tree[++tot]=x;
    int pos=tot;
    while(pos>1) {
        if(tree[pos]<tree[pos>>1])
            swap(tree[pos],tree[pos>>1]),pos>>=1;
        else break;
	}
}

删除并返回最值

把堆顶返回,然后把最底部的值放到堆顶,不断下沉去维护堆性质。下沉的时候注意左右儿子拥有最值的那个交换上来。以小根堆为例:

代码如下:

int pop() {
    int res=tree[1];
    tree[1]=tree[tot--];
    int pos=1,son=2;
    while(son<=tot) {
        if(son<tot&&tree[son|1]<tree[son])son|=1;
        if(tree[son]<tree[pos])
            swap(tree[son],tree[pos]),pos=son,son=pos<<1;
        else break;
	}
    return res;
}
posted @ 2019-01-17 21:22  AKMer  阅读(211)  评论(0编辑  收藏  举报