首先我來和大家一起了解一下堆的一些問題。堆是一個非常實用的數據結構,在一些算法的優化和一些高級數據結構上都能用到堆。比如優先隊列、hash_map、迪傑斯特拉算法(最短路的優化)等等,所以我們大家學好堆是有必要的,對我們學習高深的一些算法和數據結構非常的有用。
我所知道的堆有已下幾種:二叉堆(就是我們平常說的堆)、二項堆、斐波那契堆;其中後者都是前者的優化。今天呢,由於我的水平有限,只能和大家一起探討一下二叉堆了。
二叉堆堆的一些基本知識
二叉堆是一種特殊的堆,二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足堆特性:父結點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值,且每個結點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。當父結點的鍵值總是大於或等於任何一個子節點的鍵值時爲最大堆。 當父結點的鍵值總是小於或等於任何一個子節點的鍵值時爲最小堆。
二叉堆的存儲方式
二叉堆一般用數組來表示。例如,根結點在數組中的位置是1,第n個位置的子節點分別在2n和2n+1。因此,第1個位置的子節點在2和3,第2個位置的子節點在4和5。以此類推,這種存儲方式便於尋找父節點和子節點。如下圖兩個堆:
左圖是小根堆;右圖是大根堆
1 11 / \ / \ 2 3 9 10 / \ / \ / \ / \ 4 5 6 7 5 6 7 8 / \ / \ / \ / \ 8 9 10 11 1 2 3 4
如下是小根堆的實現過程:
#define MAXN 10000
template<typename Type>
class Heap{
private:
int size;
Type data[MAXN+1];
void siftdown( int pos );
public:
Heap();
void push( Type key );
Type pop();
void make_heap();
bool empty();
void clear();
int get_size();
};
template<typename Type>
Heap<Type>::Heap(){
size= 0; }
template<typename Type>
int Heap<Type>::get_size(){
return size; }
template<typename Type>
bool Heap<Type>::empty(){
return size== 0;}
template<typename Type>
void Heap<Type>::clear(){
size= 0; }
template<typename Type>
void Heap<Type>::siftdown( int pos ){
while( pos<<1<= size ){
int t= pos<<1;
if( (pos<<1)+ 1<= size && data[(pos<<1)+1]<data[t] ) t= (pos<<1)+ 1;
if( data[t]< data[pos] ){
Type tmp= data[t]; data[t]= data[pos]; data[pos]= tmp;
pos= t; }
else break;
}
}
template<typename Type>
void Heap<Type>::push( Type key ){
data[++size]= key;
int pos= size;
while( pos> 1 ){
if( data[pos>>1]> data[pos] ){
Type tmp= data[pos];
data[pos]= data[pos>>1]; data[pos>>1]= tmp;
pos>>= 1; }
else break;
}
}
template<typename Type>
Type Heap<Type>::pop(){
Type tmp= data[1]; data[1]= data[size];
data[size]= tmp; size--;
siftdown(1); return data[size+1];
}