堆和优先队列

优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。

优先队列的完全二叉树表示


note:0号位置是为了之后的插入操作方便,而加入的哨兵,如果在堆排序中,未给出这样的结点,则可不设置。

堆的两个特性
结构性:用数组表示的完全二叉树
局部有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)

note:①此处易和二叉搜索树进行混淆,只是局部有界

      ②判断是否是最小堆(1)完全二叉树

                        (2)从根结点到任意结点路径上结点序列的有序性!
 “最大堆(MaxHeap)”,也称“大顶堆”:最大值
 “最小堆(MinHeap)”,也称“小顶堆” :最小值

template 
class MinHeap  { 							//最小堆类定义
private:
	T* heapArray;							//存放堆数据的数组
	int CurrentSize;						//当前堆中元素数目
	int MaxSize;							//堆所能容纳的最大元素数目
	void swap(int pos_x, int pos_y);		//交换位置x和y的元素
	void BuildHeap();						//建堆
public:
	MinHeap(const int n);				 //构造函数,n表示初始化堆的最大元素数目
	virtual ~MinHeap(){delete []heapArray;}; 	//析构函数
	bool isEmpty( );							// 如果堆空,则返回真
    bool isLeaf(int pos) const;		 	    //如果是叶结点,返回TRUE
	int leftchild(int pos) const;		   	//返回左孩子位置
	int rightchild(int pos) const;			//返回右孩子位置
	int parent(int pos) const;				//返回父结点位置
	bool Remove(int pos, T& node);			//删除给定下标的元素
	bool Insert(const T& newNode);			//向堆中插入新元素newNode
	T& RemoveMin();				        	//从堆顶删除最小值
	void SiftUp(int position);			 //从position向上开始调整,使序列成为堆
	void SiftDown(int left);             //筛选法函数,参数left表示开始处理的数组下标
};
一、插入新元素——向上筛选

template
int MinHeap::leftchild(int pos) const  {
	return 2*pos + 1;						//返回左孩子位置
}

template
int MinHeap::rightchild(int pos) const  {
	return 2*pos + 2;						  //返回右孩子位置
}

template
int MinHeap::parent(int pos) const  {
	return (pos-1)/2;						   //返回父结点位置
}

template
void MinHeap::swap(int pos_x, int pos_y)     //交换位置x和y的元素
{
 T temp = heapArray[pos_x];
 heapArray[pos_x] = heapArray[pos_y];
 heapArray[pos_y] = temp;
}

template 
bool MinHeap::Insert(const T& newNode)  {  //向堆中插入新元素newNode
	if(CurrentSize == MaxSize)				   //堆空间已经满
		return FALSE;
	heapArray[CurrentSize] = newNode;      //从最后结点开始插入
	SiftUp(CurrentSize);					   //向上调整
	CurrentSize++;
	return TRUE;
}

template
void MinHeap::SiftUp(int position)  {    //从position向上开始调整,使序列成为堆 未使用哨兵
	int temppos = position;
	T temp = heapArray[temppos];
	while ((temppos>0) && (heapArray[parent(temppos)]>temp))  {
		heapArray[temppos] = heapArray[parent(temppos)];
		temppos = parent(temppos);
	}
	heapArray[temppos] = temp;
}

二、删除堆顶(取最大值或者最小值)——向下筛选
第一步:取最后的那个结点代替栈顶结点
第二步:向下筛选

template
T& MinHeap::RemoveMin()	 {				//从堆顶删除最小值
	if (CurrentSize == 0)  {
		cout<< "Can't Delete" <1)
			SiftDown(0);						//从堆顶开始筛选
		return heapArray[CurrentSize];
	}
}

template 
void MinHeap::SiftDown(int left)  {
	int i = left;								// 标识父结点
	int j = leftchild (i);							// 标识关键值较小的子结点
	T	temp = heapArray[i];					// 保存父结点
	while (j < CurrentSize) {       			    // 过筛
		if ((j < CurrentSize-1) && (heapArray[j]>heapArray[j + 1]))//左子节点存在右子节点未必存在
			j++;								// j指向右子结点
		if (temp>heapArray[j]) {
			heapArray[i] = heapArray[j];
			i = j;
			j = leftchild(j);						// 向下继续
		}
		else break;
	}
	heapArray[i] = temp;
}

三、堆的建立

建立最大(小)堆:将已经存在的N个元素按最大(小)堆的要求存放在一个一维数组中

方法1:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间代价最大为O(N logN)
建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中
方法2:在线性时间复杂度下建立最大堆。
(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性
(2)调整各结点位置,以满足最大堆的有序特性。

调整从栈顶最后一个没有子女的结点进行向下筛选

template
void MinHeap::BuildHeap()  {
	for (int i = CurrentSize/2-1; i >= 0; i--) 	//反复调用筛选函数
		SiftDown(i);
}






发布了24 篇原创文章 · 获赞 7 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览