C++——优先级队列(priority_queue)

2023-05-16

目录

 

1. 优先级队列(priority_queue)

1.1 基本概念

1.2 优先级队列的定义

1.3 通过重写仿函数来支持自定义数据类型

1.4 通过运算符重载来支持自定义比较函数

1.5 优先级队列的基本操作

2. 示例程序


1. 优先级队列(priority_queue)

1.1 基本概念

之前已经提到了队列(queue),队列是一种先进先出(First in First out,FIFO)的数据类型。每次元素的入队都只能添加到队列尾部出队时从队列头部开始出。

优先级队列(priority_queue)其实,不满足先进先出的条件,更像是数据类型中的“堆”优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义比如定义元素越大优先级越高,那么每次出队,都是将当前队列中最大的那个元素出队。个人感觉这就是所谓“优先级”的定义。

现在看优先级队列是不是就是“堆”了,如果最大的元素优先级最高,那么每次出队的就是当前队列中最大的元素,那么队列实际就相当于一个大顶堆,每次将堆根节点元素弹出,重新维护大顶堆,就可以实现一个优先级队列。

1.2 优先级队列的定义

C++中,使用优先级队列需要包含头文件<queue>,优先级队列的定义如下:

priority_queue<typename, container, functional>
  • typename是数据的类型;
  • container是容器类型,可以是vector,queue等用数组实现的容器,不能是list,默认可以用vector;
  • functional是比较的方式,默认是大顶堆(就是元素值越大,优先级越高);如果使用C++基本数据类型可以直接使用自带的less和greater这两个仿函数默认使用的是less,就是构造大顶堆,元素小于当前节点时下沉)。使用自定义的数据类型的时候,可以重写比较函数也可以进行运算符重载less重载小于“<”运算符,构造大顶堆greater重载大于“>”运算符,构造小顶堆)。

定义一个优先级队列的示例如下:

//构造一个大顶堆,堆中小于当前节点的元素需要下沉,因此使用less
priority_queue<int, vector<int>, less<int>> priQueMaxFirst;

//构造一个小顶堆,堆中大于当前节点的元素需要下沉,因此使用greater
priority_queue<string, vector<string>, greater<string>> priQueMinFirst;

1.3 通过重写仿函数来支持自定义数据类型

仿函数是通过重载“()”运算符来模拟函数操作的类

先自定义一个类Data,将id作为该类的关键字,进行比较,重写仿函数

//自定义数据类型,Data类
class Data
{
public:
	Data(int i, int d) :id(i), data(d) {}
	~Data() {}
	int getId() { return id; }
	int getData() { return data; }
private:
	int id;
	int data;
};
//重写仿函数,完成less的功能,也可以用class定义类,此时需要将运算符重载函数设为public
//结构体struct中默认是访问类型是public
struct cmp    
{
	bool operator() ( Data &a, Data &b) {
		return a.getId() < b.getId();
	}
};

int main(void){
    priority_queue<Data, vector<Data>, cmp > priQueMaxFirst;//该优先级队列维护一个大顶堆,因此最大的元素最先出队
    ...//一系列操作
    ...
    return 0;
}

1.4 通过运算符重载来支持自定义比较函数

运算符重载的话,由于是重载双目运算符,因此需要使用友元函数,我们在类内声明友元函数,在类外实现友元函数,如下:

//自定义数据类型,Data类
class Data
{
public:
	Data(int i, int d) :id(i), data(d) {}
	~Data() {}
	int getId() { return id; }
	int getData() { return data; }
	friend bool operator < (const Data &a, const Data &b);//运算符重载,友元函数可以访问类的私有成员
private:
	int id;
	int data;
};
//重载“<”运算符,仿函数less中需要使用
bool operator < (const Data &a, const Data &b) {
	return a.id < b.id;
}

int main(void){
    priority_queue<Data, vector<Data>, less<Data> > priQueMaxFirst;//该优先级队列维护一个大顶堆,因此最大的元素最先出队
    ...//一系列操作
    ...
    return 0;
}

1.5 优先级队列的基本操作

优先级队列的基本操作与普通队列类似,不同的是每次获得队内的元素是优先级最高的元素(要从堆的顶部开始),因此使用的是top()方法,而不是front()方法。如下:

  1. push() :入队。向队列添加一个元素,无返回值;
  2. pop() :将队列中优先级最高的元素出队。将队列中优先级最高的元素删除(出队),无返回值;
  3. top() :获得队列优先级最高的元素。此函数返回值为队列中优先级最高的元素,常与pop()函数一起,先通过top()获得队列中优先级最高的元素,然后将其从队列中删除;
  4. size() :获得队列大小。此函数返回队列的大小,返回值是“size_t”类型的数据,“size_t”是“unsigned int”的别名。
  5. empty() :判断队列是否为空。此函数返回队列是否为空,返回值是bool类型。队列空:返回true;不空:返回false。

2. 示例程序

程序中,使用基本数据类型“string”以及自定义数据类型Data分别构造了优先级队列。然后通过运算符重载重写仿函数支持自定义的数据类型(两种方法都写了,代码中用的是运算符重载)。

#include <iostream>
#include <queue>//使用队列需要引用<queue>头文件
#include <string>
using namespace std;
//自定义数据类型,Data类
class Data
{
public:
	Data(int i, int d) :id(i), data(d) {}
	~Data() {}
	int getId() { return id; }
	int getData() { return data; }
	friend bool operator < (const Data &a, const Data &b);//运算符重载,友元函数可以访问类的私有成员
private:
	int id;
	int data;
};
//重载“<”运算符,仿函数less中需要使用
bool operator < (const Data &a, const Data &b) {
	return a.id < b.id;
}
//重写仿函数,完成less的功能,用class的时候,需要public关键词(因为struct中默认数据是public,而class中默认是private)
class cmp
{
public:
	bool operator() ( Data &a, Data &b) {
		return a.getId() < b.getId();
	}
};

int main()
{
	//基本数据类型示例
	priority_queue<string, vector<string>, greater<string> > p;//维护一个小顶堆,最小的元素优先级最高,最先出队
	p.push("C");
	p.push("B");
	p.push("A");
	cout << p.top() << endl;//队列中优先级最高的是最后进队的“A”
	//自定义数据类型示例
	priority_queue<Data, vector<Data>, less<Data> > priQueMaxFirst;//该优先级队列维护一个大顶堆,因此最大的元素最先出队
	//构造一个优先级队列
	for (int i = 0; i < 4; ++i) {
		Data tmpData(i, 0 - i);
		priQueMaxFirst.push(tmpData);
	}
	//打印当前队列中优先级最高的元素,然后将其出队
	while (!priQueMaxFirst.empty()) {
		Data topData = priQueMaxFirst.top();//top()与pop()搭配,获得队列中优先级最高的元素,然后将其出队
		priQueMaxFirst.pop();
		cout << "ID: " << topData.getId() << " " << " Data: " << topData.getData() << endl;//打印当前队列中优先级最高的元素
	}
	return 0;
}

上述程序的输出如下:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++——优先级队列(priority_queue) 的相关文章

  • Laravel 多个工人运行两次工作

    我使用 Laravel 5 6 将作业分派到队列 然后使用主管激活该队列上的 8 个工作线程 我原以为 Laravel 会知道不要运行同一个工作两次 但我惊讶地发现它确实如此 同样的工作由不止一名工人负责 因此奇怪的事情开始发生 问题是 一
  • jQuery stop(true, true) 跳转到队列中所有动画的末尾

    我一直在使用 jQuerystop true true 方法清除正在运行的动画 以便下一个立即开始 我注意到第一个参数 clearQueue 清除整个动画队列 但第二个参数 jumpToEnd 仅跳转到当前正在运行的动画的末尾 而不是从队列
  • 用jquery编写全局动画队列

    使用 jQuery 将一系列动画添加到单个 dom 元素非常简单 jQuery 为我很好地排列了一切 我基本上不需要做任何事情 然而 在多个元素上制作一系列动画 例如 pictureDiv 淡出 然后填充人口统计Div 淡入 要困难得多 我
  • 使用队列的生产者/消费者线程

    我想创建某种Producer Consumer线程应用程序 但我不确定在两者之间实现队列的最佳方法是什么 所以我有两个想法 这两个想法都可能是完全错误的 我想知道哪个更好 如果它们都很糟糕那么实现队列的最佳方法是什么 我关心的主要是这些示例
  • 如何获取运行任务的队列 - celery

    我是新使用芹菜 有一个问题 我有这个简单的任务 app task name test install queue def test install queue return subprocess call exit 0 shell True
  • 在 MySQL 中创建链表或类似队列?

    我有一个需要按特定顺序显示的项目表 但该顺序可以更改 可以在开头 结尾或中间添加项目 并且可以重新排列项目 如何设置表来跟踪该顺序 以便易于修改 但也可以通过单个查询按顺序获取列表 例如 我可以有一个 NEXT ID 列来执行链接列表样式
  • 是否可以按值删除队列元素?

    我想从队列中删除具有特定值的元素 这样的事该怎么办呢 我正在尝试创建映射和队列的并发混合 目前我尝试在这个答案 https stackoverflow com questions 7704526 is thare in stl or boo
  • Keras 的 OrderedEnqueuer 是否保证了批次的顺序?

    我有一个习惯keras utils sequence它以特定 且关键 的顺序生成批次 但是 我需要跨多个核心并行化批量生成 名字是不是 OrderedEnqueuer 意味着结果队列中批次的顺序保证与原始队列的顺序相同keras utils
  • 如何使用 PHPmailer 构建电子邮件队列?

    在插入表后 我已经使用 PHPmailer 构建了一个电子邮件脚本 但是 由于脚本超时 我收到了错误的网关 502 发送 300 多封电子邮件来响应网络请求对我来说听起来不是一个好主意 所以我的问题是如何构建一个在后台发送电子邮件的队列 据
  • 如何在Linux中找到处理器队列长度

    尝试确定 Linux 计算机上的处理器队列长度 准备运行但当前未运行的进程数 Windows 中有一个针对此指标的 WMI 调用 但对 Linux 不太了解 我正在尝试挖掘 proc 和 top 以获取信息 有没有办法确定CPU的队列长度
  • 将 Laravel 事件订阅者排队

    我通过事件订阅者处理多个事件 而不是创建单独的事件 侦听器 我想对其中几个事件进行排队 但我还没有找到实现这一目标的方法 我已经关注官方了文档 https laravel com docs 5 2 events event subscrib
  • JMS QueueSender 线程安全吗?

    我想在多线程环境中使用 QueueSender Is QueueSender send 线程安全 No a MessageProducer QueueSender不是线程安全的 或者更具体地说 Session http java sun c
  • 持久 Akka 邮箱和无损

    在 Akka 中 当一个 actor 在处理消息时死亡 内部onReceive 该消息丢失 有没有办法保证无损 有没有办法配置 Akka 始终保留消息before将他们发送到onReceive 以便在演员死亡时可以恢复并重播 也许像持久邮箱
  • 如何在没有线程或任务队列的情况下在 Flask 中运行后台作业

    我正在使用 Flask restplus 构建 REST API 我的端点之一获取从客户端上传的文件并运行一些分析 该作业最多需要 30 秒 我不希望这项工作阻塞主进程 因此端点将立即返回 200 或 201 响应 作业仍然可以运行 结果将
  • java队列中Queue.Poll()返回null但Queue.size()>0

    My code while Memo qRcv size gt 0 MessageReceived msg Memo qRcv poll 然后我得到了 2014 03 01 11 09 36 DEBUG Thread 16 threadQu
  • 使用 Celery 创建动态队列

    这是我的场景 当用户登录我的网站时 我会为给定用户排队一堆任务 通常每个任务需要 100 毫秒 每个用户有 100 多个任务 这些任务排队到默认的 Celery 队列中 并且我有数百个工作线程正在运行 当任务在后端完成时 我使用 webso
  • Java 中保存最后 N 个元素的大小受限队列

    关于 Java 库的一个非常简单快速的问题 是否有一个现成的类可以实现Queue具有固定的最大大小 即它始终允许添加元素 但它会默默地删除头元素以为新添加的元素提供空间 当然 手动实现它很简单 import java util Linked
  • TensorFlow 队列关闭后可以重新打开吗?

    我想将项目入队 关闭队列以确保其他会话将所有剩余项目出队 然后在下一个纪元稍后重新打开它 这可能吗 q tf FIFOQueue close q q close reopen q with tf Session as sess sess r
  • cron 作业和 PHP (Zend Framework) 入门

    我对 cron 作业这个主题完全陌生 所以我不知道从哪里开始学习它们 何时 为何或如何将它们与我的 Zend Framework 应用程序或一般的 PHP 一起使用 任何人都可以通过示例解释该过程 或者推荐一些好的资源来入门吗 Cron 作
  • $(this).dequeue();与下一个();

    如果我这样做有什么区别吗 queue queue function next next queue function next next versus queue queue function this dequeue queue func

随机推荐