二叉堆類模板的實現以及使用它進行堆排序
阿新 • • 發佈:2018-12-02
二叉堆:二叉堆一棵完全二叉樹,從遞迴的定義來講,對於完全二叉樹的任何一個節點,其左孩子要麼是空樹要麼是一個完全二叉樹,右孩子同上。
堆:對於一個堆來講,可以是一個大根堆,也可以是一個小根堆。
大根堆的性質:對於在大根堆任何一個節點,其值不小於左右孩子的值。
小根堆的性質:對於在大根堆任何一個節點,其值不大於左右孩子的值。
由於堆的底層資料結構是由完全二叉樹實現的,就可以利用完全二叉樹的一些性質來實現一個堆。假設一棵完全二叉樹的編號從零開始,則對於任意節點i,其父親節點和孩子節點可以表示為。
father(i) = i/2;
left(i) = 2 * i,right(i) = 2 * i+1;
用陣列構建一個堆:由於陣列的下標是從0開始的,這樣與完全二叉樹節點從1開始不對應,實際可以這樣處理,為陣列多申請一個空間不使用索引為0的空間,這樣就可以將一棵完全二叉樹和陣列完全的對應起來,這樣處理會使得程式碼編寫更為簡單,程式碼的可讀性非常高。
template<typename T> class Heap{ private: T* data;//儲存堆中資料的陣列 int count;//記錄當前堆中有效元素的個數 int capacity;//記錄堆儲存的容量 //向上調整元素data[k]滿足堆的性質 void shiftUp(int k){ //以構建大根堆為前提條件 while(k>1 && data[k/2] < data[k]){ //若k節點的父親節點data[k/2]比自己還小,需交換位置 /*迴圈終止條件k>1,當k==2時,其父親節點為data[1]。 需注意邊界處理,否則會發生陣列越界*/ swap(data[k/2],data[k]); k /= 2;//更新節點 } } //向下調整data[k]以繼續滿足堆的性質 //對於任何一個節點,尋找max(node,max(node->left,node->right))作為當前的根節點 void shiftDown(int k){ //當前節點有右孩子 while(2*k<=count){ int j = 2*k;//j表示最終data[k]所在的位置 if(j+1 <= count && data[j+1]>data[j]){ j ++;//當前節點存在右孩子,並且右孩子大於左孩子的值 } if(data[k] > data[j]) break;//當前節點大於其左右孩子,則不需要做調整 else swap(data[k],data[j]); k = j;//更新新的根節點 } } public: Heap(int capacity){ data = new T[capacity+1];//0索引不使用 this->capacity = capacity; this->count = 0; } ~Heap(){ delete[] data;//釋放在堆上開闢的記憶體 } int size(){return count;} bool isEmpty(){return size==0;} void insert(T value){ //插入資料前需判斷是否還有空間可以插入 assert(count<capacity); data[count+1] = value; count ++; //新新增的元素可能不滿足堆的性質,需做調整維護堆的性質 shiftUp(count);//呼叫被private限定的方法,不直接暴露給使用者 } //推出堆頂元素 T extractMax(){ //需判空,如果堆空,則沒有堆頂元素 assert(count >= 1);//堆中至少由一個元素 T ans = data[1];//對於大根堆,data[1]就是此堆的最大元素 swap(data[1],data[count]);//將堆中最後一個元素和第一個元素交換位置 count --;//刪除被交換下來的最大元素 shiftDown(1);//data[count]放置到第一個位置有可能不滿足堆的性質,需做調整 return ans; } };
利用上邊已經實現的Heap的類模板實現堆排序
#include <iostream> using namespace std; //堆排序的介面 template<typename T> void heapSort(T arr[],int n){ Heap<T> hp(n+1); for(int i=0;i<n;++i){ hp.insert(arr[i]); } //從小到大排序 for(int i=n-1;i>=0;--i){ arr[i] = hp.extractMax(); } } template<typename T> void show(T arr[],int n){ for(int i=0;i<n;++i){ cout<<arr[i]<<" "; } cout<<endl; }
主函式
int main(void){
int arr[] = {8,5,9,7,3,6,4,2,1};
int n = sizeof(arr)/sizeof(int);
heapSort(arr,n);
show(arr,n);
return 0;
}
執行結果: