1. 程式人生 > >二叉堆類模板的實現以及使用它進行堆排序

二叉堆類模板的實現以及使用它進行堆排序

二叉堆:二叉堆一棵完全二叉樹,從遞迴的定義來講,對於完全二叉樹的任何一個節點,其左孩子要麼是空樹要麼是一個完全二叉樹,右孩子同上。

堆:對於一個堆來講,可以是一個大根堆,也可以是一個小根堆。

大根堆的性質:對於在大根堆任何一個節點,其值不小於左右孩子的值。
小根堆的性質:對於在大根堆任何一個節點,其值不大於左右孩子的值。

由於堆的底層資料結構是由完全二叉樹實現的,就可以利用完全二叉樹的一些性質來實現一個堆。假設一棵完全二叉樹的編號從零開始,則對於任意節點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;
}

執行結果:
在這裡插入圖片描述