[C++]优先级队列

1 .了解优先级队列

优先级队列是一种容器适配器,根据一些严格的弱排序 标准,专门设计使其第一个元素始终是它所包含的元素中最大的元素。

此上下文类似于 ,其中可以随时插入元素,并且只能检索最大堆 元素(优先级队列 中顶部的元素)。

优先级队列是作为容器适配器实现的,容器适配器 是使用特定容器类的封装对象作为其底层容器 的类,提供一组特定的成员函数来访问其元素。元素是从特定容器的*"背面"* 弹出 的,该容器称为优先级队列的顶部

基础容器可以是任何标准容器类模板,也可以是其他一些专门设计的容器类。容器应通过*随机访问迭代器*访问,并支持以下操作:

  • empty()
  • size()
  • front()
  • push_back()
  • pop_back()

标准容器类并满足这些要求。默认情况下,如果未为特定类实例指定容器类,则使用标准容器。

需要支持*随机访问迭代器* ,以便始终在内部保持堆结构。这是由容器适配器通过自动调用算法函数自动完成的,并在需要时自动完成。vector、deque、priority_queue、vector、make_heappush_heap、pop_heap

2.优先级队列的相关接口

优先级队列的接口有如下几种。对于优先级队列我们默认是它的大的数优先级高。其底层是一个堆。也就是说,我们默认是大堆,所以大的数优先级高。如果是一个小堆,那么就是小的优先级高

1.常用接口函数

我们来随便使用一下这些接口吧:

cpp 复制代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

void test_priority_queue()
{
	priority_queue<int> pq;
	pq.push(123);
	pq.push(1045);
	pq.push(2);
	pq.push(3);
	pq.push(4);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

int main()
{
	test_priority_queue();
}

运行结果:

可以看到,默认是一个大堆,但是我们会注意到,它库里面默认传的是less,但是却是一个大堆,这里需要额外注意一下。

如果想要是一个小堆的话,我们需要将这个less替换为greater:

cpp 复制代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

void test_priority_queue()
{
	priority_queue<int,vector<int>,greater<int>> pq;
	pq.push(123);
	pq.push(1045);
	pq.push(2);
	pq.push(3);
	pq.push(4);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
}

int main()
{
	test_priority_queue();
}

运行结果:

在这里我们传的less,greater这些也称之为仿函数。也就是说,通过仿函数控制实现大小堆.除此之外,这里除了可以传vector以外,还可以传递deque,但是由于堆需要大量访问[]运算符,所以deque的效率不高。

2.构造函数

如下所示,可以无参构造,也可以用迭代器区间进行初始化。

3.优先队列的模拟实现

优先级队列,主要还是堆的逻辑的实现。即堆的构造,向上调整和向下调整。

这些我们在数据结构讲过了,我直接上源码了

cpp 复制代码
	template<class T, class Container = vector<T>>
	class priority_queue
	{
	private:
		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			while (child<_con.size())
			{
				if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				{
					child++;
				}
				if (_con[child] > _con[parent])
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void AdjustUp(int 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;
				}
			}
		}

	public:
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				first++;
			}
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
		priority_queue()
		{}

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

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

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

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

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
相关推荐
捕鲸叉几秒前
C++软件设计模式之类型模式和对象型模式
开发语言·c++·设计模式
魔道不误砍柴功2 分钟前
Java 中反射的高级用法:窥探 Java 世界的魔法之门
java·开发语言·python
2401_8576176213 分钟前
“无缝购物体验”:跨平台网上购物商城的设计与实现
java·开发语言·前端·安全·架构·php
觅远13 分钟前
python+reportlab创建PDF文件
开发语言·python·pdf
我曾经是个程序员30 分钟前
C#File文件基础操作大全
开发语言·c#
捕鲸叉33 分钟前
C++软件设计模式之代理(Proxy)模式
c++·设计模式
林浔090635 分钟前
QT信号槽
开发语言·qt
重生之绝世牛码39 分钟前
Java设计模式 —— 【结构型模式】享元模式(Flyweight Pattern) 详解
java·大数据·开发语言·设计模式·享元模式·设计原则
Allen Bright1 小时前
【Java基础-26.1】Java中的方法重载与方法重写:区别与使用场景
java·开发语言
秀儿y1 小时前
单机服务和微服务
java·开发语言·微服务·云原生·架构