二叉堆學習筆記

前言

其實這東西學過兩年了……因此應該算是複習筆記吧?算法

定義

二叉堆,簡稱堆,顧名思義,是一棵二叉樹,仍是一棵徹底二叉樹。其顯著特徵是整棵樹中父結點的值與子結點的值的大小關係都相同(即父結點的值均大於兩個子結點的值或均小於兩個子結點的值)。若大於,稱之爲大根堆,小於則是小根堆。顯而易見,堆頂元素(即根節點)爲二叉堆的最大或最小元素。在存儲的時候,爲了方便,咱們能夠將整個二叉堆存到一個數組裏,以1爲根結點,某一元素兩個兒子的下標分別爲(2i)和(2i+1),父親下標爲(i/2)。數組

用途

二叉堆可用於維護一個序列的極值。它支持插入一個元素,刪除極值元素和查詢極值元素。經過拼接兩個二叉堆,咱們還能夠對刪除指定元素的操做。less

操做實現

插入

首先將元素插入二叉堆的最後,接着不斷與它的父結點比較,若不知足堆的順序則交換它與它的父結點,直到整個二叉堆從新知足二叉堆的性質(即到達堆頂或當前比較結果知足堆的順序)。code

void insert(const Type &x)
{
    a[++size]=x;
    unsigned int now=size;
    while(now>1&&!compare(a[now>>1],a[now]))
    {
        swap(a[now>>1],a[now]);
        now>>=1;
    }
    return;
}

查詢堆頂元素

直接返回根節點便可。排序

inline Type top(){return a[1];}

刪除堆頂元素

首先將堆頂元素與最後一個元素交換位置,並維護堆的大小(將堆的大小減一),則原來的堆頂元素已被刪去。接下來咱們要維護堆的性質,從堆頂元素開始,不斷把當前元素與較小兒子(大根堆爲較大)進行比較,若不知足堆的順序則交換,直到整個二叉堆從新知足堆的性質(即到達末尾或當前比較結果知足堆的順序)。class

void erase()
{
    a[1]=a[size];
    --size;
    unsigned int now=1;
    while(now<<1<=size)
    {
        unsigned int t=now<<1;
        if((t|1)<=size&&compare(a[t|1],a[t]))
            t|=1;
        if(compare(a[now],a[t]))
            break;
        swap(a[now],a[t]);
        now=t;
    }
    return;
}

刪除指定元素(拓展)

以上就是普通二叉堆的全部操做。但有時候咱們面臨的問題涉及到從堆當中刪除某一特定值的元素,這可使用兩個二叉堆拼接起來解決。咱們創建一個輔助二叉堆,二叉堆使它的排序方式與須要維護的二叉堆相同。顯然,當某一元素不是原二叉堆的堆頂元素時,它的存在與否對正確性並沒有影響,所以咱們能夠等到它變爲堆頂元素時再刪掉它。而輔助二叉堆就是用來保存還沒有刪除的數的序列的。每次遇到刪除操做時,咱們先將要刪除的元素存入輔助二叉堆。等到取堆頂元素的操做時,咱們不斷查看原二叉堆的堆頂元素是否與輔助二叉堆相等,如果則同時刪除兩個二叉堆的堆頂元素,直到原二叉堆的堆頂元素與輔助二叉堆的堆頂元素不相等。易證,當某一元素成爲原二叉堆的堆頂元素時,比它小(大根堆爲大)的元素均已被刪除,意即比它大的元素也不會存在於輔助二叉堆中,從而只有當輔助二叉堆中的堆頂元素等於原二叉堆時須要刪除,故這一算法正確。二叉樹

inline Type top()
{
    while(!a.empty()&&!t.empty()&&a.top()==t.top())
    {
        a.erase();
        t.erase();
    }
    return a.top();
}
inline void insert(const Type &x){a.insert(x);return;}
inline void erase(const Type &x){t.insert(x);return;}

總代碼

BasicHeap即爲不帶刪除指定元素操做的基本堆,Heap爲帶這一操做的堆。查詢

#ifndef _HEAP_HPP_
#define _HEAP_HPP_

template<typename Type>
class BasicHeap
{
    private:
        static const unsigned int maxn=500000;
        Type a[maxn+1];
        unsigned int size;
        bool (*compare)(const Type &a,const Type &b);
        static inline bool less(const Type &a,const Type &b){return a<b;}
        static inline void swap(Type &a,Type &b){a^=b;b^=a;a^=b;return;}
    public:
        BasicHeap(bool (*judge)(const Type &a,const Type &b)=less):size(0),compare(judge){}
        BasicHeap(const BasicHeap<Type> &b)
        {
            size=b.size;
            for(unsigned int i=1;i<=size;++i)
                a[i]=b.a[i];
        }
        inline Type top()const{return a[1];}
        inline bool empty()const{return size==0;}
        void insert(const Type &x)
        {
            a[++size]=x;
            unsigned int now=size;
            while(now>1&&!compare(a[now>>1],a[now]))
            {
                swap(a[now>>1],a[now]);
                now>>=1;
            }
            return;
        }
        void erase()
        {
            a[1]=a[size--];
            unsigned int now=1;
            while(now<<1<=size)
            {
                unsigned int t=now<<1;
                if((t|1)<=size&&compare(a[t|1],a[t]))
                    t|=1;
                if(compare(a[now],a[t]))
                    break;
                swap(a[now],a[t]);
            }
        }
};
template<typename Type>
class Heap
{
    private:
        BasicHeap<Type>a,t;
        static inline bool less(const Type &a,const Type &b){return a<b;}
    public:
        Heap(bool(*judge)(const Type &a,const Type &b)=less):a(judge),t(judge){}
        Heap(const Heap &b):a(b.a),t(b.t){}
        inline Type top()
        {
            while(!a.empty()&&!t.empty()&&a.top()==t.top())
            {
                a.erase();
                t.erase();
            }
            return a.top();
        }
        inline bool empty()const{return a.empty();}
        inline void insert(const Type &x){a.insert(x);return;}
        inline void erase(const Type &x){t.insert(x);return;}
};

#endif
相關文章
相關標籤/搜索