在C++中用堆来实现最基本的优先队列

6 篇文章 0 订阅
2 篇文章 0 订阅

许多应用程序都需要处理有序元素,但是不一定要求他们完全有序。很多情况下只需要处理当前最大元素,然后数据集合变化后再继续处理最大元素。在这种情况下,一个合适的数据结构应支持两种关键操作:1删除最大元素2插入元素。优先队列具备这种特质。优先队列可以使元素按照自定义的一个优先级来排序,并非加入顺序来排序,高效实现优先队列具有一定挑战性。

《算法》一书中介绍了维护一个二叉堆来实现高效的优先队列插入删除操作,以下是用C++编写的基于堆的优先队列:

.h 头文件

#include <vector>
#include <iostream>

using namespace std;

/*定义大顶堆模板类*/
template<typename T>
class MaxPQ
{
public:
	MaxPQ(int maxN);
	~MaxPQ();
	/*基本接口*/
	bool isEmpty();
	void insert(T val);
	T delMax();
	void swim(int k);
	void sink(int k);
	/*内部调用的工具接口*/
	friend void exchan(vector<T> &a, int j, int k);
	friend bool pqless(T & a, int x, int y);
private:

	vector<T> pq;
	int N = 0;
};
/*定义小顶堆模板类*/
template<typename T>
class MinPQ
{
public:
	MinPQ(int maxN);
	~MinPQ();

	bool isEmpty();
	void insert(T val);
	T delMin();
	void swim(int k);
	void sink(int k);

	friend void exchan(vector<T> &a, int j, int k);
	friend bool pqless(T & a, int x, int y);
private:

	vector<T> pq;
	int N = 0;
};

/*易位操作*/
template<typename T>
inline void exchan(vector<T>& a, int j, int k)
{
	T tmp;
	tmp = a[j];
	a[j] = a[k];
	a[k] = tmp;
}
/*大小比较,该函数仍然使用字典顺序来比较队列元素*/
template<typename T>
inline bool pqless(T & a,int x, int y)
{
	if (a[x] <= a[y])
		return true;
	return false;
}

二叉堆是一个部分有序的完全二叉树,因为完全二叉树可以用数组来维护,所以遍历起来比较快速

下图描述了一个小顶堆的上浮排序过程,最终得到一个顶层一定最小,而且每一层根节点都小于下一层孩子节点的完全二叉树

但是同一层是不存在优先级顺序的。

                                              

 

.cpp源文件

/*定义队列长度,初始化队列*/
template<typename T>
MaxPQ<T>::MaxPQ(int maxN)
{
	pq.assign(maxN+1, 0);
}

template<typename T>
MaxPQ<T>::~MaxPQ()
{
}

template<typename T>
bool MaxPQ<T>::isEmpty()
{
	if (N)
		return false;
	return true;
}
/*插入元素,并进行排序*/
template<typename T>
void MaxPQ<T>::insert(T val)
{
	pq[++N] = val;
	swim(N);
}
/*删除堆顶,并重构堆*/
template<typename T>
T MaxPQ<T>::delMax()
{
	T max = pq[1];
	exchan(pq,1,N--);
	sink(1);
	return max;
}
/*上浮操作,与父节点比较,并判断是否进行易位*/
template<typename T>
void MaxPQ<T>::swim(int k)
{
	while (k>1 && pqless(pq,k/2,k)) {
		exchan(pq,k/2,k);
		k = k / 2;
	}
}
/*下沉操作,需要与较大的子节点比较,并判断是否进行易位*/
template<typename T>
void MaxPQ<T>::sink(int k)
{
	while (2*k<=N) {
		int j = 2 * k;
		if (j < N && pqless(pq, j, j + 1))
			j++;
		if (!pqless(pq, k, j))
			break;
		exchan(pq,k,j);
		k = j;
	}
}


/*小顶对,修改了上浮和下沉的逻辑,其他操作与大顶堆一致*/
template<typename T>
MinPQ<T>::MinPQ(int maxN)
{
	pq.assign(maxN+1, 0);
}

template<typename T>
MinPQ<T>::~MinPQ()
{
}

template<typename T>
bool MinPQ<T>::isEmpty()
{
	if (N)
		return false;
	return true;
}

template<typename T>
void MinPQ<T>::insert(T val)
{
	pq[++N] = val;
	swim(N);
}

template<typename T>
T MinPQ<T>::delMin()
{
	T max = pq[1];
	exchan(pq, 1, N--);
	sink(1);
	return max;
}

template<typename T>
void MinPQ<T>::swim(int k)
{
	while (k > 1 && !pqless(pq, k / 2, k)) {
		exchan(pq, k / 2, k);
		k = k / 2;
	}
}

template<typename T>
void MinPQ<T>::sink(int k)
{
	while (2 * k <= N) {
		int j = 2 * k;
		if (j < N && !pqless(pq, j, j + 1))
			j++;
		if (pqless(pq, k, j))
			break;
		exchan(pq, k, j);
		k = j;
	}
}

测试用例main.cpp

#if PQUEUE_TEST
	MaxPQ<int> maxpq(5);
	MinPQ<int> minpq(5);
	maxpq.insert(1);
	maxpq.insert(2);
	maxpq.insert(3);
	maxpq.insert(4);
	maxpq.insert(5);
	minpq.insert(3);
	minpq.insert(1);
	minpq.insert(2);
	minpq.insert(4);
	minpq.insert(5);
	cout << maxpq.delMax() << " " << minpq.delMin() << endl;
	cout << maxpq.delMax() << " " << minpq.delMin() << endl;
	cout << maxpq.delMax() << " " << minpq.delMin() << endl;
	cout << maxpq.delMax() << " " << minpq.delMin() << endl;
	cout << maxpq.delMax() << " " << minpq.delMin() << endl;
#endif
	system("pause");
	return 0;

预期输出结果:

对一个大顶堆和一个小顶堆实现的优先队列分别随机插入了5个相同的元素,那么每次获取队首元素所得到

的两组输出结果应该是互为逆序

运行结果:

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值