堆的c++实现

堆,是一种完全二叉树。而且在这颗树中,父节点必然大于(对于小顶堆为小于)子节点。

关于树的概念不了解可以看这里http://blog.csdn.net/zhuyifan_jizhi/article/details/79645557

而堆分为两种,最小堆和最大堆,这里主要是讲的最小堆。

最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。

现在我们知道了堆的概念,那么,如果我们要删除最小数并往堆里增加一个数,该怎么做呢?

很显然最小的数就在堆顶,假设存储这个堆的数组是h的话,最小数就是好h[1]。接下来,我们将h[1]删除,将新增数放到堆顶。但加了新数以后,就不符合堆的特性了,所以我们需要将这个新数下调。向下调整时,我们需要将这个数与他的儿子中小的一个进行交换,直到符合堆的特性。

下调代码如下:

//向下调整函数 
void siftdown(int i){//传入一个需要调整的节点编号 
	int t,flag=0;//flag用来标记是否需要向下调整  
	while(i*2<=n && flag==0){//当节点有儿子时,循环执行  
		if(h[i]>h[i*2]) t=i*2;//首先判断它与左儿子的关系,用t记录较小的节点编号  
		else t=i;
		if(i*2+1<=n){//如果有右儿子,则对右儿子进行讨论 
			if(h[t]>h[i*2+1]) t=i*2+1;//如果右儿子更小,则更新t 
		}
		if(t!=i){
			swap(t,i);//交换函数要自己写 
			i=t;//准备继续向下调整  
		}
		else{//说明i不需要调整了  
		    flag=1; 
	    }
	} 
	return;
}

说了半天,我们忽略了一个很重要的问题,那就是如何建立堆。

代码如下:

//建立堆的函数 
void creat(){
	int i;
	for(int i=n/2;i>=1;i--)//从最后一个非叶节点到第一个节点依次调整  
	    siftdown(i);
    return;
} 

堆有一个功能就是堆排序,时间复杂度是O(NlogN)。堆排序其实很简单,比如我们要从小到大排序,只需要先建立最小堆,然后每次删除堆顶元素并输出,直到堆为空为止。

//寻找最小元素并删除 
int deletemin(){
	int t;
	t=h[1];//用一个临时的变量记录顶点的值 
	h[1]=h[n];//将堆的最后一个值赋值到堆顶 
	n--;//堆的元素减少1; 
	siftdown(1);//向下调整 
	return t;//返回之前记录的堆的顶点的最小值 
}
建堆及堆排序的完整代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int h[101];//用来存放堆
int n;
//交换函数 
void swap(int x,int y){
	int t;
	t=h[x];
	h[x]=h[y];
	h[y]=t;
	return;
}
//向下调整函数 
void siftdown(int i){//传入一个需要调整的节点编号 
	int t,flag=0;//flag用来标记是否需要向下调整  
	while(i*2<=n && flag==0){//当节点有儿子时,循环执行  
		if(h[i]>h[i*2]) t=i*2;//首先判断它与左儿子的关系,用t记录较小的节点编号  
		else t=i;
		if(i*2+1<=n){//如果有右儿子,则对右儿子进行讨论 
			if(h[t]>h[i*2+1]) t=i*2+1;//如果右儿子更小,则更新t 
		}
		if(t!=i){
			swap(t,i);//交换函数要自己写 
			i=t;//准备继续向下调整  
		}
		else{//说明i不需要调整了  
		    flag=1; 
	    }
	} 
	return;
}
//建立堆的函数 
void creat(){
	int i;
	for(int i=n/2;i>=1;i--)//从最后一个非叶节点到第一个节点依次调整  
	    siftdown(i);
    return;
} 
//寻找最小元素并删除 
int deletemin(){
	int t;
	t=h[1];//用一个临时的变量记录顶点的值 
	h[1]=h[n];//将堆的最后一个值赋值到堆顶 
	n--;//堆的元素减少1; 
	siftdown(1);//向下调整 
	return t;//返回之前记录的堆的顶点的最小值 
}
int main(){
	int num;
	cin>>num;
	for(int i=1;i<=num;i++) cin>>h[i];
	n=num;
	creat();//建堆 
	for(int i=1;i<=num;i++) cout<<deletemin()<<" "; //删除顶部元素,其实也就是从小到大把数输出来 
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/zhuyifan_jizhi/article/details/79645595
今日推荐