数据结构与算法分析(c++版) #13 堆与优先队列

       (二叉)堆是一种使用数组实现完全二叉树的数据结构,树上的每一点对应数组的一个元素。堆经常被用来实现优先队列堆排序。下面为堆的示意图。

                            

       如图,下面为计算各亲属下标的公式。公式中r表示结点的下标。它的范围在0到n - 1之间。n表示二叉树结点的总数。

       parent(r) = (r - 1) / 2       当 r ≠ 0 时

       leftChild(r) = 2r + 1         当 2r + 1 < n 时

       rightChild(r) = 2r + 2       当 2r + 2 < n 时

      

       二叉堆可以分为两种形式:最大堆和最小堆。

       在最大堆中,除了根结点以外的的所有结点 i 都需要满足:   A[ parent(i) ] >= A[ i ] ,也就是说,某个结点的值至多与其父结点一样大。因此,堆中最大的元素存放在根结点;并且在任一子树中,该子树包含的的所有结点的值都不大于子树该根结点的值。

       最小堆的性质则与最大堆刚好相反:  A[ parent(i) ] <= A [ i ] ,最小堆把最小的元素值存放在根结点。


优先队列

       一些按照重要性或优先级来组织的对象称为优先队列。我们可以用最大堆来实现优先队列,出队即把最大堆的根结点删除并返回值,然后继续维护最大堆的性质。在最大堆中,分支结点的下标为0 ~ number / 2 - 1 , 叶结点的下标为 number / 2 ~ number - 1。

下面为实现最大堆的代码:

template <class Elem> class maxheap
{
private:
	Elem* Heap;	// 存放元素的堆(数组)
	int size;	// 堆的大小
	int number;	// 堆目前存放的元素个数
	void heapify(int);	// 维持最大堆的性质,输入的值必须保证左右孩子都是最大堆
	void swap(Elem A[], int i, int j)	// 交换数组中的两个值
	{
		Elem temp = A[i]; A[i] = A[j]; A[j] = temp;
	}
public:
	maxheap(Elem* h, int s, int n) 
		: Heap(h), size(s), number(n) {	buildHeap(); }	// 初始化成员并建堆
	~maxheap() {}
//	判断是否叶结点
	bool isLeaf(int pos) const { return (pos >= number / 2) && (pos < number); }
//	返回堆的元素个数
	int heapSize() const { return number; }
//	返回输入结点下标的左孩子的下标
	int leftChild(int pos) const { return (pos << 1) + 1; }
//	返回输入结点下标的右孩子的下标
	int rightChild(int pos) const { return (pos << 1) + 2; }
//	返回输入结点下标的父结点下标
	int parent(int pos) const { return (pos - 1) >> 1; }
//	向堆中插入元素,成功返回true
	bool insert(const Elem&);
//	删除堆中值最大的元素,即根结点,并返回其值,成功返回true
	bool removeMax(Elem&);
//  提高指定位置结点元素的值(修改优先级)
	bool increasePri(int,const Elem&);
//	建堆
	void buildHeap()
	{
		for (int i = number / 2 - 1; i >= 0; --i)	//只对分支结点执行
			heapify(i);	// 分别维持最大堆的性质
	}
};

// 维持最大堆的性质,输入时要求保证其左右结点也是最大堆
template <class Elem>
void maxheap<Elem>::heapify(int pos)
{
	while (!isLeaf(pos))	// 只对分支结点执行,用来中止向下传递到叶结点的情况
	{
		int left = leftChild(pos);	// 取左孩子下标, 并用来存放左右孩子中的最大值
		int right = rightChild(pos);	// 取右孩子下标
		if ((right < number) && (Heap[left] < Heap[right]))	// 若存在右孩子且大于左孩子
			left = right;
		if ((Heap[pos] > Heap[left])) return;	// 若该结点大于其孩子结点值,直接退出函数
		swap(Heap, pos, left);	// 把最大元素值与原来值交换
		pos = left;	// 向下延伸
	}
}

//	向堆中插入元素,成功返回true
template <class Elem>
bool maxheap<Elem>::insert(const Elem& elem)
{
	if (number >= size) return false;
	int current = number++;	// 堆元素个数加一,并用存起原来的副本
	Heap[current] = elem;	// 把元素插到数组末尾,即为叶结点
	// 新插入的结点与父结点比较,当current为0时跳过,因为是根结点
	while ((current != 0) && (Heap[current] > Heap[parent(current)]))	
	{
		swap(Heap, current, parent(current));
		current = parent(current);	// 向上攀爬
	}
	return true;
}

//	删除堆中值最大的元素,即根结点,并返回其值,成功返回true
template <class Elem>
bool maxheap<Elem>::removeMax(Elem& elem)
{
	if (number == 0) return false;
	swap(Heap, 0, --number);	// 用根结点的值与最后一个结点的值交换,并把长度减一,相当于删除根结点
	if (number != 0) //	如果还有元素
		heapify(0);
	elem = Heap[number];
	return true;
}
//  提高指定位置结点元素的值(修改优先级)
template <class Elem>
bool maxheap<Elem>::increasePri(int pos, const Elem& elem)
{
	if (Heap[pos] > elem) return false;	// 原来的优先级比现在低
	Heap[pos] = elem;	// 提高优先级
	while ((pos != 0) && (Heap[pos] > Heap[parent(pos)]))
	{	
		swap(Heap, pos, parent(pos));
		pos = parent(pos);	//向上攀爬
	}
	return true;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值