template<typename Item>classMaxHeap{private:
Item *data;int count;int capacity;voidshiftUp(int k){while( k >1&& data[k/2]< data[k]){swap( data[k/2], data[k]);
k /=2;}}voidshiftDown(int k){while(2*k <= count ){int j =2*k;// 在此輪循環中,data[k]和data[j]交換位置if( j+1<= count && data[j+1]> data[j])
j ++;// data[j] 是 data[2*k]和data[2*k+1]中的最大值if( data[k]>= data[j])break;swap( data[k], data[j]);
k = j;}}public:// 構造函數, 構造一個空堆, 可容納capacity個元素MaxHeap(int capacity){
data =new Item[capacity+1];
count =0;this->capacity = capacity;}// 構造函數, 通過一個給定數組創建一個最大堆// 該構造堆的過程, 時間複雜度爲O(n)MaxHeap(Item arr[],int n){
data =new Item[n+1];
capacity = n;for(int i =0; i < n ; i ++)
data[i+1]= arr[i];
count = n;for(int i = count/2; i >=1; i --)shiftDown(i);}~MaxHeap(){delete[] data;}// 返回堆中的元素個數intsize(){return count;}// 返回一個布爾值, 表示堆中是否爲空boolisEmpty(){return count ==0;}// 像最大堆中插入一個新的元素 itemvoidinsert(Item item){assert( count +1<= capacity );
data[count+1]= item;shiftUp(count+1);
count ++;}// 從最大堆中取出堆頂元素, 即堆中所存儲的最大數據
Item extractMax(){assert( count >0);
Item ret = data[1];swap( data[1], data[count]);
count --;shiftDown(1);return ret;}// 獲取最大堆中的堆頂元素
Item getMax(){assert( count >0);return data[1];}};
5.堆排序
// heapSort1, 將所有的元素依次添加到堆中, 在將所有元素從堆中依次取出來, 即完成了排序// 時間複雜度均爲O(nlogn)template<typename T>voidheapSort1(T arr[],int n){
MaxHeap<T> maxheap = MaxHeap<T>(n);for(int i =0; i < n ; i ++)
maxheap.insert(arr[i]);for(int i = n-1; i >=0; i--)
arr[i]= maxheap.extractMax();}
優化1(heapify)
依據:因爲可以把葉子節點看作是已經滿足二叉堆
// heapSort2, 藉助我們的heapify過程創建堆// 時間複雜度爲O(nlogn),比上述heapSort1性能更優, 因爲創建堆的性能更優template<typename T>voidheapSort2(T arr[],int n){
MaxHeap<T> maxheap = MaxHeap<T>(arr,n);for(int i = n-1; i >=0; i--)
arr[i]= maxheap.extractMax();}
優化2(原地堆排序)
// 原始的shiftDown過程template<typename T>void__shiftDown1(T arr[],int n,int k){while(2*k+1< n ){int j =2*k+1;if( j+1< n && arr[j+1]> arr[j])
j +=1;if( arr[k]>= arr[j])break;swap( arr[k], arr[j]);
k = j;}}// 優化的shiftDown過程, 使用賦值的方式取代不斷的swap,// 該優化思想和我們之前對插入排序進行優化的思路是一致的template<typename T>void__shiftDown(T arr[],int n,int k){
T e = arr[k];while(2*k+1< n ){int j =2*k+1;if( j+1< n && arr[j+1]> arr[j])
j +=1;if( e >= arr[j])break;
arr[k]= arr[j];
k = j;}
arr[k]= e;}// 不使用一個額外的最大堆, 直接在原數組上進行原地的堆排序template<typename T>voidheapSort(T arr[],int n){// 注意,此時我們的堆是從0開始索引的// 從(最後一個元素的索引-1)/2開始// 最後一個元素的索引 = n-1for(int i =(n-1-1)/2; i >=0; i --)__shiftDown2(arr, n, i);for(int i = n-1; i >0; i--){swap( arr[0], arr[i]);__shiftDown(arr, i,0);}}