关于cpp的优先级队列(堆)

本文介绍了C++中的优先级队列,重点讨论了大根堆和小根堆的使用场景,尤其是何时选择向上调整和向下调整方法,以及如何通过仿函数灵活切换比较器。作者还给出了优先级队列的简单模拟实现和测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  优先级队列其实就是一个堆,在cpp库里面默认为一个大根堆,它和双端队列一样,是一个容器适配器,默认用vector作为容器,类似数组。另外为了灵活的变换生成大根堆还是小根堆,可以用cpp的库(#include<functional>)里的仿函数来控制。

  初学的时候对什么时候用向上调整好,什么时候用向下调整好把握不准,以大根堆为例,我个人认为在用迭代器初始化和进行删除的时候用向下调整好,插入的时候用向上调整好。删除的时候,是top的值与尾部互换后,再把尾部pop_back掉,需要调整的元素在顶部,所以只能用向下调整,而插入的时候是把元素插在尾部(vector),此时需要调整的元素在尾部,所以只能使用向上调整法。

  而用迭代器初始化的时候,用向上调整和向下调整都可以达到目的,但是一看发现,使用向上调整时调用的函数次数会比向下调整建堆调用的函数次数要多,也就是资源的浪费,所以初始化的时候建议用向下调整建堆。

  关系仿函数的补充
  仿函数其实是一个类,它的里面会重写一个(),然后写一个的功能函数(一般多为比较大小等简单的函数)放在重写的()函数内,然后在类外实例化后就可以像函数一样使用,所以称为 仿函数 ,比如在模拟实现优先级队列中,它就是默认使用一个less仿函数(功能就是<)作为比较器,stl中默认使用的是greater作为比较器,这样使用者就可以通过显示传比较器来选择大根堆还是小根堆。

  使用库里面的堆需要包头文件(<queue>),别忘了它是容器适配器,第二个模板参数可以决定它是用链表还是集合来作为它的数据结构。

  cpp的优先级队列简单模拟实现及测试

#pragma once
#include<iostream>
#include<vector>
#include<functional>
namespace hzj
{
	using namespace std;
	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	private:
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_com(_c[parent],_c[child]))
				{
					std::swap(_c[parent], _c[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else break;
			}
		}
		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			int len = size();
			while (child < len)
			{
				if (child + 1 < len && _com(_c[child] , _c[child + 1])) child++;
				if (_com(_c[parent],_c[child]))
				{
					std::swap(_c[child], _c[parent]);
					parent = child;
					child = child * 2 + 1;
				}
				else break;
			}
		}
	public:
		priority_queue()
		{}
		template<class inputiterator>
		priority_queue(inputiterator first, inputiterator last)
		{
			inputiterator it = first;
			while (it != last)
			{
				_c.push_back(*it);
				++it;
			}
			for (int i = (size() - 2) / 2; i >= 0;i--)
			{
				AdjustDown(i);
			}
		}
		bool empty()const
		{
			return _c.empty();
		}
		size_t size()const
		{
			return _c.size();
		}
		const T& top()
		{
			return _c[0];
		}
		void push(const T& x = new T())
		{
			 _c.push_back(x);
			 AdjustUp(size() - 1);
		}
		void pop()
		{
			std::swap(_c[0], _c[size() - 1]);
			_c.pop_back();
			AdjustDown(0);
		}
	private:
		Container _c;
		Compare _com;
	};
	void test1()
	{
		priority_queue<int> pq;
		pq.push(1);
		pq.push(2);
		pq.push(3);
		pq.push(4);
		while (!pq.empty())
		{
			cout << pq.top() << " ";
			pq.pop();
		}
		cout << endl;
	}
	void test2()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
		priority_queue<int> pq(v.begin(), v.end());
		while (!pq.empty())
		{
			cout << pq.top() << " ";
			pq.pop();
		}
		cout << endl;
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值