优先级队列

文章目录

priority_queue的介绍

priority_queue文档介绍

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

priority_queue的使用

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆

常用函数接口:

默认大的优先级高,底层是大堆:

cpp 复制代码
void test1()
{
	//默认大的优先级高,底层是大堆
	priority_queue<int> pq;
	pq.push(2);
	pq.push(1);
	pq.push(5);
	pq.push(4);
	pq.push(3);
	
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

改成小堆:

cpp 复制代码
void test2()
{
	//改成小堆
	priority_queue<int, vector<int>, greater<int>> pq;
	pq.push(2);
	pq.push(1);
	pq.push(5);
	pq.push(4);
	pq.push(3);

	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

priority_queue<int, vector<int>, greater<int>> pq;第三个参数是比较函数,它决定了优先队列中元素的排序方式。在这里,greater是一个函数对象,表示使用从大到小的顺序进行排序,也就是创建了一个小顶堆。

greater<int>实际上是一个仿函数,什么是仿函数呢?下面将介绍

仿函数

cpp 复制代码
//仿函数,它的对象可以像函数一样使用
template<class T>
struct Less
{
	bool operator()(const int& x, const int& y)
	{
		return x < y;
	}
};

int main()
{
	Less<int> lsfunc;
	cout << lsfunc(1, 2) << endl;
	cout << lsfunc.operator()(1, 2) << endl;
	cout << Less<int>()(1, 2) << endl;
	cout << Less<int>().operator()(1, 2) << endl;

	return 0;
}
  • cout << lsfunc(1, 2) << endl;:调用仿函数实例lsfuncoperator(),输出结果为1(即true)。
  • cout << lsfunc.operator()(1, 2) << endl;:显式调用lsfuncoperator(),输出结果也是1
  • cout << Less()(1, 2) << endl;:创建一个临时的Less对象并立即调用其operator(),输出结果为1
  • cout << Less().operator()(1, 2) << endl;:创建一个临时的Less对象并显式调用其operator(),输出结果为1

模拟实现

插入:

cpp 复制代码
void adjust_up(size_t child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_con[child] > _con[parent])
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

adjust_up函数接受一个参数child,表示当前需要向上调整的节点的索引。在函数中,通过计算child的父节点索引parent,然后不断比较父节点和子节点的大小关系,如果父节点比子节点小,则交换它们的位置,并更新child和parent的值。循环会一直进行,直到子节点比父节点小或者已经到达根节点。


删除:

cpp 复制代码
void adjust_down(size_t parent)
		{
			Compare com;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					++child;
				}

				//if (_con[child] > _con[parent])
				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

cpp 复制代码
bool empty()
		{
			return _con.empty();
		}

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

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

优先队列模拟实现完整代码

cpp 复制代码
#pragma once

#include <iostream>
using namespace std;

#include <vector>
// priority_queue--->堆
namespace bite
{
	template<class T>
	struct less
	{
		bool operator()(const T& left, const T& right)
		{
			return left < right;
		}
	};

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

	template<class T, class Container = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		// 创造空的优先级队列
		priority_queue() : c() {}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: c(first, last)
		{
			// 将c中的元素调整成堆的结构
			int count = c.size();
			int root = ((count - 2) >> 1);
			for (; root >= 0; root--)
				AdjustDown(root);
		}

		void push(const T& data)
		{
			c.push_back(data);
			AdjustUP(c.size() - 1);
		}

		void pop()
		{
			if (empty())
				return;

			swap(c.front(), c.back());
			c.pop_back();
			AdjustDown(0);
		}

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

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

		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const T& top()const
		{
			return c.front();
		}
	private:
		// 向上调整
		void AdjustUP(int child)
		{
			int parent = ((child - 1) >> 1);
			while (child)
			{
				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					child = parent;
					parent = ((child - 1) >> 1);
				}
				else
				{
					return;
				}
			}
		}

		// 向下调整
		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < c.size())
			{
				// 找以parent为根的较大的孩子
				if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))
					child += 1;

				// 检测双亲是否满足情况
				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}
	private:
		Container c;
	};
}

void TestQueuePriority()
{
	bite::priority_queue<int> q1;
	q1.push(5);
	q1.push(1);
	q1.push(4);
	q1.push(2);
	q1.push(3);
	q1.push(6);
	cout << q1.top() << endl;

	q1.pop();
	q1.pop();
	cout << q1.top() << endl;

	vector<int> v{ 5,1,4,2,3,6 };
	bite::priority_queue<int, vector<int>, bite::greater<int>> q2(v.begin(), v.end());
	cout << q2.top() << endl;

	q2.pop();
	q2.pop();
	cout << q2.top() << endl;
}
相关推荐
‘’林花谢了春红‘’9 分钟前
C++ list (链表)容器
c++·链表·list
机器视觉知识推荐、就业指导2 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Yang.994 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王4 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_4 小时前
C++自己写类 和 运算符重载函数
c++
六月的翅膀4 小时前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++
liujjjiyun5 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥5 小时前
c++中mystring运算符重载
开发语言·c++·算法
天若有情6736 小时前
c++框架设计展示---提高开发效率!
java·c++·算法