堆的物理实现(大根堆+小根堆)

  • 说明
  • 基于顺序表实现的堆

一、说明

1、堆是一颗完全二叉树,因此能用一维数组来存储堆,但堆本质上是一种实现了“局部有序”的树结构。

2、最大堆:任何一个结点存储的值都大于或等于任意一个子结点存储的值。根结点存储着最大值。
     最小堆:任何一个结点存储的值都小于或等于任意一个子结点存储的值。根结点存储着最小值。

3、本文中存储堆的数组下标从0开始。则下标为i的左孩子结点为lc=2*i+1,右孩子结点为rc=2*i+2,双亲结点为parent=(i-1)/2。

4、插入一个新元素it时,只需将堆的大小加1,把it放在堆的末端,然后对it进行sift_up(上移)操作。所需时间Θ(log n)。

5、删除第i项元素时,用堆中最后一个元素来取代Heap[i],然后根据被删除元素和取代它的元素的优先级,来确定对取代它的元素是做sift_up(上移)还是sift_down(下移)操作。所需时间Θ(log n)。

6、删除堆顶时,用堆中最后一个元素来取代堆顶元素,将堆的大小减1,然后对it进行sift_down(下移)操作。所需时间Θ(log n)。

7、堆的建立有两种方法:①对于一个空堆,用insert操作来建堆,插入n个元素,所需的执行时间是Θ(n log n);②直接在数组中调整,单结点的二叉树是堆,在完全二叉树中所有以叶子结点(序号i>=n/2)为根的子树是堆,这样,只需要依次将以序号为n/2-1,n/2-2,...,0的结点为根的子树调整为堆即可,所需的执行时间为Θ(n)。

8、下述堆的实现有两个模板参数,第一个E是堆中的数据类型,第二个Comp是比较优先级的。若要实现某种堆则调用相对应的Comp类。

 

二、基于顺序表实现的堆

1、Comp_max.h(调用该类实现最大堆)

#include<iostream>
using namespace std;
#ifndef _Comp_max
#define _Comp_max
namespace wangzhe
{
	template<typename E>
	class Comp_max
	{
		public:
			static bool prior(E a, E b)//注意要是静态函数 
			{
				return a>=b;
			}
	};
}
#endif 

2、Comp_min.h(调用该类实现最小堆)

#include<iostream>
using namespace std;
#ifndef _Comp_min
#define _Comp_min
namespace wangzhe
{
	template<typename E>
	class Comp_min
	{
		public:
			static bool prior(E a, E b)//注意要是静态函数 
			{
				return a<=b;
			}
	};
}
#endif 

3、heap.h

#include<iostream>
using namespace std;
#include"Comp_max.h"
#ifndef _heap
#define _heap
namespace wangzhe
{
	template<typename E,typename Comp>
	class heap
	{
		private:
			E* Heap; //堆 
			int maxsize;//最大结点数 
			int n;//当前结点数 
			void sift_down(int pos)//向下调整 
		        {
		    	        while(!isLeaf(pos))
				{
		    		        int j=lc(pos),r=rc(pos);
		    		        if(r<n&&(Comp::prior(Heap[r],Heap[j]))) j=r;
		    		        if(Comp::prior(Heap[pos],Heap[j])) return;
		    		        swap(Heap[pos],Heap[j]);
		    		        pos=j;
				}
			}
			void sift_up(int pos)//向上调整 
			{
				while(pos)
				{
					int j=parent(pos);
					if(Comp::prior(Heap[j],Heap[pos])) return;
					swap(Heap[pos],Heap[j]);
					pos=j;
				}
			} 
		public:
			heap(E* h,int num,int max);//构造函数
			int size() const;//当前堆的大小
			bool isEmpty();//判断当前堆是否为空 
			bool isLeaf(int pos) const;//判断是否是叶结点
			int lc(int pos) const;//左孩子
			int rc(int pos) const;//右孩子
			int parent(int pos) const;//双亲
			void buildHeap();//建堆
			E top();//返回堆顶 
			void insert(const E& it);//添加一个结点
			E removefirst();//删除堆顶 
			E remove(int pos);//删除第pos个结点 
				 
	};
}
#endif

4、heap.cpp

#include<iostream>
#include<algorithm> 
using namespace std;
#include"heap.h"
namespace wangzhe
{
	
	template<typename E,typename Comp>
	heap<E,Comp>::heap(E* h,int num,int max)
	{
		Heap=h,n=num,maxsize=max;
		buildHeap(); 
	}
	
	template<typename E,typename Comp>
	int heap<E,Comp>::size() const
	{
		return n;
	}
	
	template<typename E,typename Comp>
	bool heap<E,Comp>::isEmpty() 
	{
		return n==0;
	}
	
	template<typename E,typename Comp>
	bool heap<E,Comp>::isLeaf(int pos) const
	{
		return (pos>=n/2)&&(pos<n);
	}
	
	template<typename E,typename Comp>
	int heap<E,Comp>::lc(int pos) const
	{
		return 2*pos+1;
	}
	
	template<typename E,typename Comp>
	int heap<E,Comp>::rc(int pos) const
	{
		return 2*pos+2;
	}
	
	template<typename E,typename Comp>
	int heap<E,Comp>::parent(int pos) const
	{
		return (pos-1)/2;
	}
	
	template<typename E,typename Comp>
	void heap<E,Comp>::buildHeap()
	{
	    for(int i=n/2-1;i>=0;i--)
			sift_down(i);	
	} 
	
	template<typename E,typename Comp>
	E heap<E,Comp>::top()
	{
		if(n<=0)
		{
			cout<<"Heap is empty\n";
			exit(-1);
		}
		return Heap[0];
	} 
	
	template<typename E,typename Comp>
	void heap<E,Comp>::insert(const E& it)
	{
		if(n>=maxsize)
		{
			cout<<"Heap is full\n";
			return;
		}
		Heap[n++]=it;
		sift_up(n-1);
 	}
 	
 	template<typename E,typename Comp>
 	E heap<E,Comp>::removefirst()
 	{
 		if(n<=0) 
		{
			//cout<<"Heap is empty\n";
			exit(-1); 	
	        }	
	        swap(Heap[0],Heap[--n]);
	        if(n!=0) sift_down(0);
	   	return Heap[n];//返回被删掉的元素,原先是Heap[0] 
	}
	
	template<typename E,typename Comp>
	E heap<E,Comp>::remove(int pos) 
	{
		if(pos<0||pos>=n) 
		{
			cout<<"Bad position\n";
			exit(-1);
		}
		if(pos==n-1) n--;
		else 
		{
			int x=Heap[pos],y=Heap[--n];
			swap(Heap[pos],Heap[n]);
			if(Comp::prior(x,y)) sift_down(pos);
			else sift_up(pos);
		}
		return Heap[n];
	} 
}

5、main.cpp

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#include"Comp_max.h"
#include"heap.h"
#include"heap.cpp" 
using namespace wangzhe;
int main(int argc, char** argv) 
{
	int n,a[10010];
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	
	heap< int,Comp_max<int> > hp(a,n,10010);
	while(!hp.isEmpty())
	cout<<hp.removefirst()<<endl;
	cout<<endl;
	
	hp.insert(100);
	hp.insert(1999);
	cout<<hp.top()<<endl;
	cout<<"size:"<<hp.size()<<endl;
        hp.remove(0);
        cout<<hp.top()<<endl;
}

 

运行结果

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值