二叉堆类模板的实现以及使用它进行堆排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ASJBFJSB/article/details/84075322

二叉堆:二叉堆一棵完全二叉树,从递归的定义来讲,对于完全二叉树的任何一个节点,其左孩子要么是空树要么是一个完全二叉树,右孩子同上。

堆:对于一个堆来讲,可以是一个大根堆,也可以是一个小根堆。

大根堆的性质:对于在大根堆任何一个节点,其值不小于左右孩子的值。
小根堆的性质:对于在大根堆任何一个节点,其值不大于左右孩子的值。

由于堆的底层数据结构是由完全二叉树实现的,就可以利用完全二叉树的一些性质来实现一个堆。假设一棵完全二叉树的编号从零开始,则对于任意节点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;
}

执行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ASJBFJSB/article/details/84075322
今日推荐