C++ STL : 模拟实现STL中的容器适配器priority_queue


priority_queue

文档介绍

文档介绍

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元 素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特 定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭 代器访问,并支持以下操作:
  • empty():检测容器是否为空
  • size():返回容器中有效元素个数
  • front():返回容器中第一个元素的引用
  • push_back():在容器尾部插入元素
  1. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指 定容器类,则使用vector。
  2. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap和pop_heap来自动完成此操作。

实现思路

思路

优先级队列priority_queue就是数据结构中的堆, 作为容器适配器,其底层默认使用的容器是连续存储的vector,然后通过向下调整算法将vector调整为堆的结构,所以完全可以服用之前实现heap的代码,只需要在复用原有代码的基础上增加stl的特性即可。

下面是之前数据结构篇章时实现的堆
堆的实现

仿函数

由于C语言不能很好的支持泛型编程,所以当我们实现想分别实现大堆和小堆的时候就得修改其中的代码,但是由于C++具有模板,就完全可以通过仿函数和模板来实现代码的复用。

什么是仿函数? 其实就是使一个类能够像函数一样使用,要做到这一点只需要重载它的()运算符即可,只需要分别实现大小判断的仿函数,就可以做到分别实现大小堆

	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

这里的greater是小堆,less是大堆。
实现了之后只需要在模板中传递对应的仿函数即可实现大小堆的选择
在这里插入图片描述
库中默认是大堆

实现

#include<vector>

namespace lee
{
	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	template <class T, class Container = std::vector<T>, class Compare = less<T> >
	class priority_queue
	{
	public:
		priority_queue()
		{}

		template<class iterator>
		priority_queue(iterator begin, iterator end) : _con(begin, end)
		{
			for (int i = (_con.size() - 2) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}

		void AdjustUp(size_t child)
		{
			size_t parent = (child - 1) / 2;

			while (child > 0)
			{
				if (_com(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);
				}
				else
				{
					break;
				}

				child = parent;
				parent = (child - 1) / 2;
			}
		}

		void AdjustDown(size_t root)
		{
			size_t parent = root;
			size_t child = parent * 2 + 1;

			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _com(_con[child], _con[child + 1]))
				{
					++child;
				}

				if (_com(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);
				}
				else
				{
					break;
				}

				parent = child;
				child = parent * 2 + 1;
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);

			AdjustUp(_con.size() - 1);
		}

		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);

			_con.pop_back();
			AdjustDown(0);
		}

		const T& top() const 
		{
			return _con[0];
		}

		bool empty() const
		{
			return _con.empty();
		}

		size_t size() const
		{
			return _con.size();
		}

	private:
		Container _con;
		Compare _com;
	};
}

猜你喜欢

转载自blog.csdn.net/qq_35423154/article/details/106549262