其實這東西學過兩年了……因此應該算是複習筆記吧?算法
二叉堆,簡稱堆,顧名思義,是一棵二叉樹,仍是一棵徹底二叉樹。其顯著特徵是整棵樹中父結點的值與子結點的值的大小關係都相同(即父結點的值均大於兩個子結點的值或均小於兩個子結點的值)。若大於,稱之爲大根堆,小於則是小根堆。顯而易見,堆頂元素(即根節點)爲二叉堆的最大或最小元素。在存儲的時候,爲了方便,咱們能夠將整個二叉堆存到一個數組裏,以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