【STL】priority_queue的底层原理及其实现

news2024/11/19 7:30:47

文章目录

  • priority_queue的介绍
  • 库中priority_queue的使用
    • 什么叫仿函数?
  • 模拟实现prioprity_queue类

priority_queue的介绍

在这里插入图片描述
解释以上内容

  1. priority_queue(优先级队列)跟stack、queue一样,都是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大或者最小的(默认最大)。
  2. .优先队列的底层数据结构是用堆来实现的。
  3. 作为容器适配器,priority_queue默认是由 vector类
    来实现的。优先队列(堆)这种数据结构需要快速随机访问元素的能力。除了vector,deque类也可以用来作为优先队列的底层容器。严格来说,只要满足以下能力的容器都可以作为优先队列的底层容器:
    (1)empty():检测容器是否为空
    (2)size():返回容器中有效元素个数
    (3)front():返回容器中第一个元素的引用
    (4)push_back():在容器尾部插入元素
    (5)pop_back():删除容器尾部元素

库中priority_queue的使用

虽然我们将priority_queue称为优先队列,但是其本质就是堆,而堆的本质又是一颗完全二叉树。所以,我们需要一种符合以上这些数据结构所有特点的容器来存储元素。vector就显得非常合适。可以用下标映射节点的父子关系,高效尾删,快速随机访问。

现在我们来看库中priority_queue主要有哪些功能吧

函数声明接口说明
priority_queue()和priority_queue(first, last)构造一个空的优先队列
empty()检测优先级队列是否为空,是返回true,否则返回false
top()返回堆顶元素的值,即当前优先队列中的最大值或者最小值
push(val)在优先队列中插入val,并且调整优先队列
pop()弹出堆顶元素,即优先队列的最大值或者最小值

1.使用演示:创建大堆,默认就是最大堆在这里插入图片描述
2.使用演示:创建最小堆, 将第三个模板参数换成greater比较方式
在这里插入图片描述
其中,greater是一个类模板,实例化出来之后可以当函数一样使用(仿函数)。greater里面控制了比较对象的关系,是一个比较剂。

什么叫仿函数?

仿函数又叫函数对象。本质是一个类实例化出来的对象,因为重载了()我们可以像使用函数一样使用其operator()
比如下面就是一个仿函数:

class fun {
public:
	int operator()(int& A, int& B) {
		return A + B;
	}

};

我们可以创建一个fun类来调用operator():

class fun {
public:
	int operator()(int& A, int& B) {
		return A + B;
	}
};
void test3() {
	fun f;
	int a = 1;
	int b = 2;
	cout << f(a, b) << endl;
}

借用模板之后,仿函数比普通函数显得更加灵活
priority_queue<int, vector<int>, greater<int>>中的greater其实就是一个函数对象,通过实例化int类型,来控制两个int类型变量的顺序关系。
模拟实现greater类:

template<class T>
class Greater {
public:
	bool operator()(T& A, T& B) {
		return A > B;
	}
};

当我们将greater作为第三个参数传递给priority_queue时,二叉树的父子节点的关系也就确定了,即确定了优先级。

那为什么默认是小堆呢?
在这里插入图片描述
这是因为priority_queue的第三个参数的缺省值设置成了less,而less其实就是一个仿函数,控制了堆顶元素永远是最小值。

当然,我们同样可以不用仿函数做参数,用一个函数指针也可以达到一样的效果

值得注意的是,如果priority_queue的元素是自定义类型,那我们需要在自定义类型中提供比较运算符的重载,以便达到我们想要的目的
给出以下代码示例:

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 
 bool operator<(const Date& d)const
 {
 return (_year < d._year) ||
 (_year == d._year && _month < d._month) ||
 (_year == d._year && _month == d._month && _day < d._day);
 }
 
 bool operator>(const Date& d)const
 {
 return (_year > d._year) ||
 (_year == d._year && _month > d._month) ||
 (_year == d._year && _month == d._month && _day > d._day);
 }
 
 friend ostream& operator<<(ostream& _cout, const Date& d)
 {
 _cout << d._year << "-" << d._month << "-" << d._day;
 return _cout;
 }
 
private:
 int _year;
 int _month;
 int _day;
};
 
void TestPriorityQueue()
{
 // 大堆,需要用户在自定义类型中提供<的重载
 priority_queue<Date> q1;
 q1.push(Date(2018, 10, 29));
 q1.push(Date(2018, 10, 28));
 q1.push(Date(2018, 10, 30));
 cout << q1.top() << endl;
 
 // 如果要创建小堆,需要用户提供>的重载
 priority_queue<Date, vector<Date>, greater<Date>> q2;
 q2.push(Date(2018, 10, 29));
 q2.push(Date(2018, 10, 28));
 q2.push(Date(2018, 10, 30));
 cout << q2.top() << endl;
}

模拟实现prioprity_queue类

#define _CRT_SECURE_NO_WARNINGS 1
#include<vector>
#include<algorithm>

template<class T>
class Less {
public:
	bool operator()(T& A, T& B) {
		return A < B;
	}

};

template<class T>
class Greater {
public:
	bool operator()(T& A, T& B) {
		return A > B;
	}

};



template<class T,class Container=std::vector<T>, class Compare = Less<T> >
class priority_queue {
public:
	int size() {
		return _con.size();
	}
	bool empty() {
		return _con.empty();
	}

	void adjust_up(int n) {
		int child = n;
	    int father = (n - 1) / 2;
		Compare com;
		while (child >= 0) {
			if (com(_con[father], _con[child])) {
				std::swap(_con[father], _con[child]);
				child = father;
				father = (child - 1) / 2;
			}
			else {	
				break;
			}
		}
	}

	void adjust_down(int n) {
		int father = n;
		int child = father * 2 + 1;
		Compare com;
		while (child < size()) {
			if (child + 1 < size() && com(_con[child ],_con[child+1])) {
				child++;
			}

			if (com(_con[father], _con[child])) {
				std::swap(_con[father], _con[child]);
				father = child;
				child = child * 2 + 1;
			}
			else {
				break;
			}

		}
	}

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

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

	void pop() {
		std::swap(_con[0], _con[size() - 1]);
		_con.pop_back();
		adjust_down(0);
	}
	T& operator[](size_t n) {
		return _con[n];
	}
private:
	Container _con;
};


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

产生死锁的四个必要条件

产生死锁的四个必要条件 互斥使用: 一个资源每次只能被一个线程使用。这意味着如果一个线程已经获取了某个资源&#xff08;比如锁&#xff09;&#xff0c;那么其他线程就必须等待&#xff0c;直到该线程释放资源。 不可抢占: 已经获得资源的线程在释放资源之前&#xff0c;不…

[leetcode] all-nodes-distance-k-in-binary-tree 二叉树中所有距离为 K 的结点

. - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树&#xff08;具有根结点 root&#xff09;&#xff0c; 一个目标结点 target &#xff0c;和一个整数值 k 。 返回到目标结点 target 距离为 k 的所有结点的值的列表。 答案可以以 任何顺序 返回。 示例 1&#xff1a…

一文了解ERC404协议

一、ERC404基础讲解 1、什么是ERC404协议 ERC404协议是一种实验性的、混合的ERC20/ERC721实现的&#xff0c;具有原生流动性和碎片化的协议。即该协议可让NFT像代币一样进行拆分交易。是一个图币的互换协议。具有原生流动性和碎片化的协议。 这意味着通过 ERC404 协议&#xf…

键值数据库Redis——Windows环境下载安装+命令行基本操作+Java操纵Redis

文章目录 前言一、下载与安装&#xff08;Windows环境&#xff09;** 检查数据库连接状态 **** 查看Redis数据库信息 ** 二、Redis五种数据结构与基本操作获取所有的key——keys *清空所有的key——flushall2.1 字符串操作2.2 散列操作2.3 列表操作2.4 集合操作2.5 位图操作 三…

【Java EE】 IoC详解(Bean的存储)

文章目录 &#x1f38d;Controller&#xff08;控制器存储&#xff09;&#x1f338;如何从Spring容器中获取对象&#xff08;ApplicationContext&#xff09;&#x1f338;获取bean对象的其他方式&#xff08;BeanFactory&#xff09;&#x1f338;Bean 命名约定&#x1f338;…

Java调用http接口的几种方式(HttpURLConnection、OKHttp、HttpClient、RestTemplate)

Java作为后端语言是开发接口实现功能供客户端调用接口&#xff0c;这些客户端中最主要是本项目的前端&#xff1b;但有时候也需要Java请求其他的接口&#xff0c;比如需要长连接转短链接&#xff08;请求百度的一个接口可以实现&#xff09;、获取三方OSS签名、微信小程序签名、…

数据结构(六)----串

目录 1.串的定义 2.串的基本操作 3.串的存储结构 (1)串的定义 •顺序存储 •链式存储 (2)求串长 (3)求子串 (4)比较串的大小 (5)定位操作 4.字符串的模式匹配 (1)朴素模式匹配算法 (2)KMP算法 •求模式串中的next数组&#xff08;重点&#xff09; •练习&#…

第四百六十回

文章目录 1. 概念介绍2. 方法与细节2.1 获取方法2.2 使用细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取当前系统语言"相关的内容&#xff0c;本章回中将介绍如何获取时间戳.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

适配器模式:连接不兼容接口的桥梁

在软件开发中&#xff0c;适配器模式是一种结构型设计模式&#xff0c;它允许不兼容的接口之间进行交互&#xff0c;从而使它们能够一起工作。这个模式经常用于系统升级或集成第三方库的时候&#xff0c;当现有的代码无法直接使用新系统或库提供的接口时&#xff0c;适配器可以…

基于Java+Vue的中国咖啡文化宣传网站(源码+文档+包运行)

一.系统概述 本课题是根据咖啡文化宣传需要以及网络的优势建立的一个中国咖啡文化宣传网站&#xff0c;来实现中国咖啡文化宣传以及咖啡商品售卖的功能。 本中国咖啡文化宣传网站应用Java技术&#xff0c;MYSQL数据库存储数据&#xff0c;基于SSMVue框架开发。在网站的整个开发…

【QT入门】Qt自定义控件与样式设计之自定义QLineEdit实现搜索编辑框

往期回顾 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置-CSDN博客 【QT入门】Qt自定义控件与样式设计之自定义QLin…

找不到mfc110u.dll怎么办,总结5种有效的解决方法

在日常操作计算机的过程中&#xff0c;我们时常会遭遇各类突发状况&#xff0c;其中一种颇为常见的问题便是当试图运行某个特定软件时&#xff0c;系统突然弹出一则令人困扰的错误提示&#xff1a;“由于找不到mfc110u.dll&#xff0c;无法继续执行代码”。这个问题通常是由于缺…

Vol.44 一个分享网站的网站,每个月8.7万访问量

哈咯&#xff0c;各位朋友好啊&#xff0c;我是欧维&#xff0c;今天要给大家分享的网址是Fuun.fun&#xff0c;奇趣网站收藏家&#xff1b; 它的网址是&#xff1a;FUUN.FUN 这是一个我经常逛的网站&#xff0c;为什么我经常逛呢&#xff1f;因为可以从中发现一些有意思的网站…

Vol.46 一个在线小游戏网站,每个月50万访问量

大家好&#xff0c;我是欧维Ove&#xff0c;今天要给大家分享的网站是&#xff1a;小霸王&#xff0c;这是一个可以在线玩小霸王游戏的网站&#xff0c;网址是&#xff1a;小霸王&#xff0c;其樂無窮。紅白機&#xff0c;FC線上遊戲&#xff0c;街機遊戲&#xff0c;街機線上&…

一种驱动器的功能安全架构介绍

下图提供了驱动器实现安全功能的架构 具有如下特点&#xff1a; 1.通用基于总线或者非总线的架构。可以实现ethercat的FSOE&#xff0c;profinet的profisafe&#xff0c;或者伺服本体安全DIO现实安全功能。 2.基于1oo2D架构&#xff0c;安全等级可以达到sil3。 3.高可用性。单…

第17天:信息打点-语言框架开发组件FastJsonShiroLog4jSpringBoot等

第十七天 本课意义 1.CMS识别到后期漏洞利用和代码审计 2.开发框架识别到后期漏洞利用和代码审计 3.开发组件识别到后期漏洞利用和代码审计 一、CMS指纹识别-不出网程序识别 1.概念 CMS指纹识别一般能识别到的都是以PHP语言开发的网页为主&#xff0c;其他语言开发的网页识…

攻防世界---Web_php_include

1.题目链接 2.补充知识&#xff1a; 3.构造&#xff1a;执行成功 /?pagedata://text/plain,<?php phpinfo()?> 4.构造下面url&#xff0c;得到目录路径 /?pagedata://text/plain,<?php echo $_SERVER[DOCUMENT_ROOT]?> 5构造下面url&#xff0c;读取该路径的…

Alibaba --- 如何写好 Prompt ?

如何写好 Prompt 提示工程&#xff08;Prompt Engineering&#xff09;是一项通过优化提示词&#xff08;Prompt&#xff09;和生成策略&#xff0c;从而获得更好的模型返回结果的工程技术。总体而言&#xff0c;其实现逻辑如下&#xff1a; &#xff08;注&#xff1a;示例图…

【C++杂货铺】模板进阶

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 泛型编程 &#x1f4c1; 函数模板 &#x1f4c2; 概念 &#x1f4c2; 格式 &#x1f4c2; class 和 typename &#x1f4c2; 原理 &#x1f4c2; 函数模板实例化 &#x1f4c2; 匹配原则 &#x1f4c1; 类模板 &#x1…

全球历年GDP增长率_探数API数据统计

以下是数据的详细说明&#xff1a; 全球GDP增长最快的年份是1964年&#xff0c;全球GDP增速达到6.65%。2021年的GDP增长率也相当高&#xff0c;主要受2020年衰退后的恢复性增长推动。 全球GDP增长最慢的年份包括&#xff1a;1974年、1975年&#xff08;第一次石油危机引发&…