C++【STL】之priority_queue学习

优先级队列

优先级队列priority_queue也是STL库中容器适配器的一种,常用于进行数据优先级的处理,说到这儿是不是发现有些熟悉,没错它和我们之前讲解的堆本质上就是一个东西,底层都是数组存储的完全二叉树,它在STL库中进行了完美的封装并加入了泛型编程的思想呈现出来

文章目录:

  • 优先级队列
    • 1. 优先级队列的使用
      • 1.1 构造函数
      • 1.2 常用接口
      • 1.3 优先级切换
    • 2. 优先级队列模拟实现
      • 2.1 push方法
      • 2.2 pop方法
      • 2.3 判空大小堆顶
      • 2.4 仿函数
      • 2.5 完整代码

1. 优先级队列的使用

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。

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

  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
    empty():检测容器是否为空
    size():返回容器中有效元素个数
    front():返回容器中第一个元素的引用
    push_back():在容器尾部插入元素

  5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。

  6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

1.1 构造函数

优先级队列有两种构造方式,可以使用默认构造一个空对象,也可以通过迭代器区间进行构造

默认构造

int main()
{
	priority_queue<int> pq;	//默认构造一个空对象
	cout << typeid(pq).name() << endl;
	return 0;
}

默认的比较方式为less,会生成大堆

迭代器区间构造

int main()
{
	vector<int> v = { 1, 2, 3, 4, 5, 6 };
	priority_queue<int, deque<int>, greater<int>> pq(v.begin(), v.end());	//生成小堆
	cout << typeid(pq).name() << endl;

	while (!pq.empty())
	{
		//打印堆中元素
		cout << pq.top() << " ";
		pq.pop();
	}
	return 0;
}

这里将比较方式改为 greater 后,就会生成 小堆

1.2 常用接口

这里列举常用接口的使用,感兴趣的大佬们可以前往官方文档了解更多细节

  • empty()接口:判空
  • size()接口:查看大小
  • top()接口:查看堆顶元素
  • push():向堆中插入元素
  • pop():删除堆顶元素
int main()
{
	vector<int> v = { 24,45,33,12,65,88,52,66 };
	priority_queue<int> pq(v.begin(), v.end());	//默认生成大堆
    
	cout << "empty:" << pq.empty() << endl; //判空
	cout << "size:" << pq.size() << endl; //查看大小
	cout << "top:" << pq.top() << endl; //查看堆顶元素
	cout << "------------------------" << endl;

	//插入操作
	pq.push(8);
	pq.push(112);
	cout << "empty:" << pq.empty() << endl;
	cout << "size:" << pq.size() << endl;
	cout << "top:" << pq.top() << endl;
	cout << "------------------------" << endl;

	//删除堆顶元素
	pq.pop();
	pq.pop();
	cout << "empty:" << pq.empty() << endl;
	cout << "size:" << pq.size() << endl;
	cout << "top:" << pq.top() << endl;
	cout << "------------------------" << endl;
	return 0;
}

1.3 优先级切换

创建优先级队列时,默认的比较方式缺省值为less,使用的是仿函数,默认生成大堆,想要创建小堆的话,需要将比较方式设置为grater,不过小于less是大堆,大于grater是小堆,嗯…这就点奇怪

注意:

如果要修改比较方式的话,模板参数2的底层容器也需要指明,因为比较方式是模板参数3,缺省参数规定不能跳跃缺省

priority_queue<int, deque<int>, greater<int>> pq(v.begin(), v.end());	//生成小堆

2. 优先级队列模拟实现

我们先来实现没有加入仿函数的版本

2.1 push方法

插入数据,只需尾插数据,然后遵循大小堆的规则将父子节点进行比较,向上调整即可

//向上调整
void adjust_up(int child)
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
    	//大堆 parent > chiled
        if (_con[child] > _con[parent])
        {
            swap(_con[child], _con[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

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

2.2 pop方法

删除数据,只需将堆顶数据交换到堆底,删除堆底元素,然后遵循大小堆的规则将父子节点进行比较,从堆顶向下调整即可

//向下调整
void adjust_down(int parent)
{
    size_t child = parent * 2 + 1;
    while (child < _con.size())
    {
        if (child + 1 < _con.size()
            && _con[child + 1] > _con[child) //找出较大的孩子
        {
            ++child;
        }

        //大堆 parent > 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);
}

2.3 判空大小堆顶

empty()方法:判空,复用底层容器的判空接口即可

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

size()方法:查看大小,复用底层容器查看大小接口即可

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

top()方法:查看堆顶元素:返回数组首元素即可

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

想要使用小堆的话需要将代码中的 > 改为 <,这样的手动切换方式,就显得太挫了,那么是否有姐解决方法呢?答案是有的,那就是本文的周重头戏,使用仿函数来解决

2.4 仿函数

仿函数的主要作用是 借助类和运算符重载,做到同一格式兼容所有函数

下面我们用两个比较大小的仿函数来解决上面优先级队列的实现中不能大小堆自由切换的问题

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;
    }
};

再加入第三个模板参数,也就是用于比较大小的仿函数,缺省值为less

template<class T, class Container = vector<T>, class Comapre = less<T>>

当需要进行逻辑比较时,只需要调用 operator() 进行比较即可

下面来改写向上调整和向下调整

void adjust_up(int child)
{
    Comapre com;
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        //child > parent -> parent < child
        //if (Comapre()(_con[parent], _con[child]) //匿名
        if (com(_con[parent], _con[child]))
        {
            swap(_con[child], _con[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

void adjust_down(int parent)
{
    size_t child = parent * 2 + 1;
    while (child < _con.size())
    {
        Comapre com;
        if (child + 1 < _con.size()
            && com(_con[child], _con[child + 1])) //找出较大的孩子
        {
            ++child;
        }

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

这样就可以实现大小堆的自由切换了

2.5 完整代码

#pragma once
#include <iostream>
#include <list>
#include <vector>
#include <deque>
#include <algorithm>
#include <string>
using namespace std;

namespace sakura
{
	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 = vector<T>, class Comapre = less<T>>
	class priority_queue
	{
	public:
		void adjust_up(int child)
		{
			Comapre com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//child > parent -> parent < child
				//if (Comapre()(_con[parent], _con[child]) //匿名
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				Comapre com;
				if (child + 1 < _con.size()
					&& com(_con[child], _con[child + 1])) //找出较大的孩子
				{
					++child;
				}

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

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

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
        
		const T& top()
		{
			return _con[0];
		}

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

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

	private:
		Container _con;
	};

C++【STL】之priority_queue学习,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/31237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式(二十二):行为型之备忘录模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

华为OD机试真题 JavaScript 实现【最短木板长度】【2022Q4 100分】,附详细解题思路

一、题目描述 小明有 n 块木板&#xff0c;第 i ( 1 ≤ i ≤ n ) 块木板长度为 ai。 小明买了一块长度为 m 的木料&#xff0c;这块木料可以切割成任意块&#xff0c;拼接到已有的木板上&#xff0c;用来加长木板。 小明想让最短的木板尽量长。 请问小明加长木板后&#xff0c…

Android12之执行adb disable-verity后android无法启动(一百五十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

前沿应用丨大规模无人机集群与“虚实结合”半实物仿真系统

一、应用背景 无人机集群在军事、安全、救援、航空监测、物流配送等领域具有广泛的应用前景。它可以提高任务执行的效率、灵活性和安全性&#xff0c;同时降低人力资源的需求和风险&#xff0c;无人机集群研究涉及多个学科领域&#xff0c;如机器人学、控制理论、通信技术和人工…

Verilog | 基4 booth乘法器

上接乘法器介绍 原理 跟基2的算法一样&#xff0c;假设A和B是乘数和被乘数&#xff0c;且有&#xff1a; A ( a 2 n 1 a 2 n ) a 2 n − 1 a 2 n − 2 … a 1 a 0 ( a − 1 ) B b 2 n − 1 b 2 n − 2 … b 1 b 0 \begin{align}A&(a_{2n1}a_{2n})a_{2n−1}a_{2n−2}……

【ARIMA-LSTM】合差分自回归移动平均方法-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

基于Nginx1.22+PHP8+MySQL8安装Discuz! X3.5

基于Nginx1.22PHP8MySQL8安装Discuz! X3.5 1. 安装PHP82. 安装MySQL83. 配置Nginx1.224. 安装Discuz! X3.5 1. 安装PHP8 更新系统&#xff1a; yum update安装EPEL存储库&#xff1a; yum install epel-release安装Remi存储库&#xff08;提供了最新的 PHP 版本&#xff09;&…

阿里云主机详解:ECS/轻量/虚拟主机/GPU/裸金属/云电脑详解

阿里云云主机分为云虚拟主机、云服务器ECS、轻量应用服务器、GPU云服务器、弹性裸金属服务器、专有宿主机、FPGA云服务器、高性能计算E-HPC、无影云电脑等&#xff0c;阿里云百科来详细说下阿里云云主机详解&#xff1a; 目录 阿里云云主机 云服务器ECS 轻量应用服务器 云…

python数字猜谜2.0

改进了一下数字猜谜&#xff1a; 开头&#xff0c;可选等级&#xff1a; import random guess -1 c 0 print("数字猜谜游戏&#xff01;") n input("选择等级 A B C&#xff1a;") if (n "A") or (n "a"):guess random.randint…

学习css样式的第二章

1.CSS 布局 - display 属性 display 属性是用于控制布局的最重要的 CSS 属性。 display 属性 display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline 块级元素…

JavaEE课程设计——校园招聘管理系统(vue框架分析)

目录 Vue架构 登录 Vue架构 前端执行命令 npm run serve 这是整个前端的目录结构 vue.config.js是对前端vue的一个配置&#xff0c; // var webpack require(webpack); const path require(path)function resolve(dir) {return path.join(__dirname, dir) }function pu…

centos下的Nginx的安装

1.Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占有内存少&#xff0c;并发能力强。 其他服务器介绍&#xff1a;Apache服务器、Tomcat服务器、Lighttpd服务器 2.nginx依赖安装 yum -y instal…

【数据分享】1929-2022年全球站点的逐月平均海平面压力数据(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 对于具体到监测站点的气象数据&#xff0c;之前我们分享过1929-2022年全球气象…

Opencv-C++笔记 (9) : opencv-多通道分离和合并

文章目录 一、概论二、多通道分离函数split()三、多通道合并函数merge()四、图像多通道分离与合并例程 一、概论 在图像颜色模型中不同的分量存放在不同的通道中&#xff0c;如果我们只需要颜色模型的某一个分量&#xff0c;例如只需要处理RGB图像中的红色通道&#xff0c;可以…

数据结构与算法之堆排序

目录 堆排序概述代码实现时间复杂度堆排序概述 堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。…

基于SSM的电影院购票系统开源啦

大家好&#xff0c;今天给大家带来一款SSM的电影院售票系统&#xff0c;非常不错的一个项目&#xff0c;学习javaweb编程必备。 下载地址在文末 1.SpringMVC Spring MVC属于SpringFrameWork的后续产品&#xff0c;已经融合在Spring Web Flow 里面。Spring 框架提供了构建 Web …

香橙派4 2. 驱动usb2.0芯片cy7c68013

0. 环境 - 香橙派4&#xff08;Orangepi4_2.1.2_ubuntu_bionic_desktop_linux4.4.179.img&#xff09; - EZ-USB FX2LP CY7C68013A USB 核心板 1. 下载FX3_SDK_1.3.4_linux EZ-USB™ FX3 Software Development Kit https://www.infineon.com/cms/en/design-support/tools/sdk…

实时在线云消费机、考勤门禁控制器、网络读卡器服务端C# Socket源码

消费机UDP通讯协议介绍&#xff1a; 设备向服务器发送的指令格式&#xff0c;每个字段用半角逗号(,)分隔。序号指令名称指令格式指令说明示例1响应服务器的搜索100,包序列号,终端IP,子网掩码,网关IP,远程电脑主机IP,端口号,终端硬件号响应电脑发出的搜寻局域网内所有终端设备指…

VCL界面控件DevExpress VCL v23.1.3全新首发 - 支持Windows 11新主题

DevExpress VCL Controls是Devexpress公司旗下最老牌的用户界面套包&#xff0c;所包含的控件有&#xff1a;数据录入、图表、数据分析、导航、布局等。该控件能帮助您创建优异的用户体验&#xff0c;提供高影响力的业务解决方案&#xff0c;并利用您现有的VCL技能为未来构建下…

设计模式之模板方法模式笔记

设计模式之模板方法模式笔记 说明Template Method(模板方法)目录模板方法模式示例类图抽象类包菜类菜心类测试类 说明 记录下学习设计模式-模板方法模式的写法。JDK使用版本为1.8版本。 Template Method(模板方法) 意图:定义一个操作中的算法骨架&#xff0c;而将一些步骤延…