基本数据结构——二叉堆

迅速补档,为A*做一下铺垫…

概念定义

二叉堆就是一个支持插入、删除、查询最值的数据结构。他其实是一棵完全二叉树。那么堆一般分为大根堆和小根堆

大根堆

树中的任意一个节点的权值都小于或者等于其父节点的权值,则称该二叉树满足大根堆性质。

小根堆

树中的任意一个节点的权值都大于或者等于其父节点的权值,则称该二叉树满足小根堆性质。

习惯用法

一般习惯把堆用数组保存。才用父子二倍的编号方式。即:对于某一个节点x,其左儿子节点为2*x,右儿子节点为x*2+1

支持功能及代码实现

Insert插入

向二叉堆中插入一个节点。我们首先把这个节点放在堆的末尾,然后再向上层层递归更新。时间复杂度为O(log N)

int heap[Size],n;
void up(int p){
    while(p>1){
        if(heap[p]>heap[p/2]){
            swap(heap[p],heap[p/2]);
            p/=2;
        }
        else{
            break;
        }
    }
}
void Insert(int val){
    heap[++n]=val;
    up(n);
} 

注:编者在写这篇博文的时候,由于内容过于基础,所以手速大约为20迈。如若有代码错误,敬请指出与纠正。

GetTop取首

返回二叉堆堆顶的值,时间复杂度O(1)

int GetTop(){
    return heap[1];
}

Extract去首

操作原理是将堆首取出,然后与堆尾发生交换,然后通过自减操作删除堆尾,再进行一次向下更新。时间复杂度为O(log N)

void Down(int p){
    int s=p*2;//p的左儿子
    while(s<=n){
        if(s<n&&heap[s]<heap[s+1]){
            s++;//取左右两儿子中较大者的编号 
        }
        if(heap[s]>heap[p]){
            swap(heap[s],heap[p]);
            //这里是大根堆,所以如果子节点大于父节点,是不满足性质的。
            p=s,s=p*2; 
        }
        else{
            break;
        }
    } 
}
void Extract(){
    heap[1]=heap[n--];
    down(1);
}

Remove删除

这个操作实现把下标为p的节点删除。这玩意和Extract相似,把heap[p]和heap[n]交换,然后n自减。但这时候到底需要向下更新还是向上更新并不好说。所以我们两个都要。

void Remove(int k){
    heap[k]=heap[n--];
    up(k);
    Down(k);
}

STL助你偷懒

写了那么多废话,然而STL里有一个priority_queue(优先队列)实现了一个大根堆。支持push插入,top取首,pop去首。然而没有Remove这种定点删除的操作。考虑到A*算法用的是小根堆,这其实对A*并没什么卵用。保险起见…我去翻了一下小蓝书…发觉……

STL可以实现小根堆,是我在口胡(口头胡扯)……

虽然STL真的只支持大根堆…但是我们可以喂他吃一个魅惑菇啊!!

就是说,我们通过重载“<”运算符,让STL认为大就是小,小即是大!你说的黑不是黑~

那,为了防止我们正常使用"<",我们选择用结构体让他重载。

struct rec{
    int id;
    double val;
};
bool operator <(const rec &a,const rec &b){
    return a.val>b.val;
}

题目中的Show Time

啊只要你想到处都能Show,我还有事我先走了(逃)。

 

posted @ 2019-07-21 19:42  L1ngYi  阅读(216)  评论(0编辑  收藏  举报