其实这东西学过两年了……因此应该算是复习笔记吧?算法
二叉堆,简称堆,顾名思义,是一棵二叉树,仍是一棵彻底二叉树。其显著特征是整棵树中父结点的值与子结点的值的大小关系都相同(即父结点的值均大于两个子结点的值或均小于两个子结点的值)。若大于,称之为大根堆,小于则是小根堆。显而易见,堆顶元素(即根节点)为二叉堆的最大或最小元素。在存储的时候,为了方便,咱们能够将整个二叉堆存到一个数组里,以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