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

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

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

.h 头文件

#include 
#include 

using namespace std;

/*定义大顶堆模板类*/
template
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 &a, int j, int k);
	friend bool pqless(T & a, int x, int y);
private:

	vector pq;
	int N = 0;
};
/*定义小顶堆模板类*/
template
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 &a, int j, int k);
	friend bool pqless(T & a, int x, int y);
private:

	vector pq;
	int N = 0;
};

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

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

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

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

                                              在C++中用堆来实现最基本的优先队列_第1张图片

 

.cpp源文件

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

template
MaxPQ::~MaxPQ()
{
}

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

template
MinPQ::~MinPQ()
{
}

template
bool MinPQ::isEmpty()
{
	if (N)
		return false;
	return true;
}

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

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

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

template
void MinPQ::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 maxpq(5);
	MinPQ 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个相同的元素,那么每次获取队首元素所得到

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

运行结果:

 在C++中用堆来实现最基本的优先队列_第2张图片

 

你可能感兴趣的:(C++,容器,数据结构)