【C++】详解STL的适配器容器之一:优先级队列 priority_queue

news2024/11/28 4:35:17

目录

堆算法

概述

向下调整建堆

向上调整建堆

建堆算法

仿函数

概述

使用介绍

emtpy

size

top

push

pop

模拟实现

仿函数

框架

向下调整算法

向上调整算法

pop

push

empty

top


要理解优先级队列,需要有如下知识

STL容器之一的vector,小编写了写了五千字长文详解了vector容器,不过大家只需要知道vector是什么即可http://t.csdnimg.cn/tz9y6

堆算法,虽然小编在学C语言的时候写过一篇,但本篇内容会详细讲解堆算法

仿函数,仿函数属于STL六大组件之一,小编也会精讲

堆算法

概述

小编在学习C语言时写过一篇堆排序,详见http://t.csdnimg.cn/pT5Vw

堆在结构上是一颗二叉树,这颗二叉树只能是满二叉树或完全二叉树。这颗树上的所有数据存放在类似于数组的顺序表中,用顺序表来管理树的数据。(顺序表是一种数据结构,它的底层是线性的空间——存储数据的空间是连续的)

树上的数据是按层序的顺序存入顺序表。如下图

那么顺序表的下标就代表树的节点。父亲节点,左孩子节点,右孩子节点的下标关系如下

左孩子节点的下标等于父亲节点的下标乘2加1
右孩子节点的下标等于左孩子节点的下标加1
父亲节点的下标等于左孩子节点的下标减1除2
左孩子节点的下标等于右孩子节点的下标减1

到这里大家也看出来了,我们所谓的树结构只是想象的实际是我们管理的只是类似于数组的顺序表通过上述公式便可以达到顺序表是一颗树形结构的效果

为什么非要搞一颗树形结构呢

实际上,只用用树形结构存储数据的话,和顺序表,链表比是没有任何优势的。如果存储数据时加上某些限制,便可以高效的对数据进行排序,查找等。

本来顺序表的排序效率是O(N^2),但如果顺序表管理的是一颗树形结构,那么它的排序效率会被降到O(N * lgN)。O(N * lgN)的效率在所有排序效率中属于第一梯队

那么在堆存储数据时,存数据时的限制是:父亲节点存入的数据要大于或小于孩子节点存入的数据,如果是大于就是大堆,如果是小于就是小堆

大堆特性:堆顶的数据是最大的,因为堆顶的节点是所有节点的父亲节点,而存数据时父亲节点存入的数据要大于孩子节点存入的数据,所以堆顶的数据是最大的。

小堆特性:堆顶的树据是最小的,原因同上。

向下调整建堆

如果某一个数据使堆不符合堆的结构,便可以使用向下调整算法。核心逻辑如下

恢复成小堆

从父亲节点开始

比较出左孩子节点和右孩子节点较小的节点

父亲节点是否大于孩子节点

是:交换父亲节点和孩子节点,并继续比较

否:终止整个逻辑

时间复杂度分析:

交换数据最坏的情况下是交换高度次——lgN次。效率是O(lgN)

向上调整建堆

与向上调整建堆相似,也是一种恢复堆结构的算法。

它是从孩子节点开始,向上比较父亲节点。向上调整建堆是不用比较左右孩子的。每个孩子节点有且只有一个父亲节点

时间复杂度分析:

交换数据最坏的情况下是交换高度次——lgN次。效率是O(lgN)

建堆算法

如果顺序表中的数据不是一个数据不符合堆结构,而是所有或大部分数据都不符合堆结构呢

建堆算法就是让顺序表中的无序的数据按照堆结构排序,使顺序表符合堆的结构。

核心逻辑非常简单:

最后一个父亲节点开始往前遍历每一个节点,每遍历一个节点就调用一次向下调整算法

最后一个父亲节点的下标等于最后一个孩子节点的下标减1除2

时间复杂度

关于建堆的时间复杂度参考小编的另一篇文章

不推公式,形象理解堆排序的时间复杂度:

http://t.csdnimg.cn/HfH1G

仿函数

仿函数是C++的STL的六大组件之一

从名字上理解,它具有函数的功能,但不是函数。如果从实现的角度讲的话,叫函数对象比较贴切——有函数功能的对象

再通俗一点,就是一个里对 ( ) 进行了运算符重载,不清楚运算符重载的话可参考http://t.csdnimg.cn/1NksT

重载之后,该实例化的对象即可像函数以样调用,不管从写法还是效果上,与函数无异。如下示意

template <class T>  //仿函数 比较是否大于  模板
class Less  
{
public:
	bool operator()(const T& x, const T& y)   
	{
		return x < y; //如果 x y是自定义类型,那么 < 便是自定义类型的赋值重载(前提是自定义类型支持 < 的赋值重载)
	}
};

Less less;//实例化对象

int i = less(3, 5);//像函数一样调用

仿函数的出现是为了代替函数指针。首先函数指针的定义是很繁琐的,可读性极差(虽然可以定义别名)。整个STL的设计都是泛型编程,指针很死板,不适合泛型编程。

概述

到此,所有的知识铺垫完毕,那么什么是优先级队列呢,如下图示意

优先级队列实际上还是堆。

vector容器承担顺序表这一数据结构,堆算法负责管理vector容器中的数据,仿函数是为了控制大堆和小堆

优先级队列不提供迭代器,也就是说优先级队列不支持元素遍历。

优先级队列核心功能是入数据和出数据。入数据优先级队列会调用向下调整算法或向上调整算法建堆,出数据会只会出最值

使用介绍

emtpy

判断队列是否为空

size

返回队列数据个数

top

返回堆顶数据

push

入数据

pop

删除数据

模拟实现

仿函数

template <class T>  //仿函数 比较是否小于
class Less  
{
public:
	bool operator()(const T& x, const T& y)   
	{
		return x < y; //如果 x y是自定义类型,那么 < 便是自定义类型的赋值重载(前提是自定义类型支持 < 的赋值重载)
	}
};

template <class T> //仿函数  比较是否大于
class Greater
{

public:
	bool operator()(const T& x, const T& y)     
	{
		return x > y;
	}
};

类里的成员函数一定要设计成共有,因为优先级队列要访问。

框架

template <class T, class  Container = std::vector<T>, class Comapre = Less<T>> 
//三个模板参数,<类型, 容器, 仿函数> 

class priorit_queue
{ 
	


//......


private:
	Container con;//容器

};

向下调整算法

//向下调整建堆
void AdjustDown(size_t father)
{
	//私有接口,不需要检查坐标的合法性

	Comapre compare; //实例化对象 ,比较大于还是小于传仿函数即可     

	size_t child = father * 2 + 1; //左孩子的坐标  

	while (child < con.size()) 
	{
		if (child + 1 < con.size() && compare(con[child], con[child + 1])) 
		{
			child += 1;
		}

		if (compare(con[father], con[child]))
		{
			std::swap(con[father], con[child]); //交换两个节点  

			father = child;   //更改下标
			child = father * 2 + 1;
		}
		else
		{
			break; //终止循环
		}
	}
};

向上调整算法

void AdjustUp(size_t child)
{
	Comapre compare; //实例化对象      
	size_t father = (child - 1) / 2;

	while (child > 0) 
	{
		if (compare(con[father], con[child]))
		{
			std::swap(con[father], con[child]);
			child = father;
			father = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}


}

向上调整算法和向下调整算法设计成私有即可

pop

void pop() //删除数据
{
				std::swap(con[0], con[con.size() - 1]); //首尾交换   
   
				con.pop_back(); //删除尾部数据

				AdjustDown(0);//重新建堆
};

push

void push(const T& x) //插入数据
{
				con.push_back(x);  //尾插
				AdjustUp(con.size() - 1); //向上调整算法
};

empty

bool empty() const //判断是否为空
{
				return con.size() == 0;
}

top

const T& top() const  //返回堆顶元素
{
                return con[0];
}

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

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

相关文章

嵌入式:基于STM32的RFID访问控制系统

在商业和住宅建筑中&#xff0c;访问控制系统是确保安全的关键组件。使用射频识别&#xff08;RFID&#xff09;技术&#xff0c;我们可以创建一个安全、方便的门禁系统。本教程将详细说明如何使用STM32微控制器实现RFID基础的门禁系统&#xff0c;该系统能够控制电子锁并记录访…

品鉴中的品鉴笔记:如何记录和分享自己的品鉴心得

品鉴云仓酒庄雷盛红酒的过程&#xff0c;不仅是品尝美酒&#xff0c;更是一次与葡萄酒深度对话的旅程。为了更好地记录和分享自己的品鉴心得&#xff0c;养成写品鉴笔记的习惯是十分必要的。 首先&#xff0c;选择一个适合的记录工具。可以是传统的笔记本&#xff0c;也可以是…

爆!1688「搜索推广」实操打法,8大要点快速上手!

想要1688平台上提高商品的搜索排名和曝光率&#xff0c;吸引更多的潜在客户并提升销量&#xff0c;店雷达将尽量具体地介绍相关操作方法和运营思路&#xff0c;建议大家收藏起来慢慢看。 一、了解1688平台搜索方式 1、品搜&#xff1a;这是买家最常用的搜索方式&#xff0c;通…

消息中间件是什么?有什么用?常见的消息中间件有哪些?

1.什么是消息中间件&#xff1f; 消息中间件基于队列模型在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。 2.现实中的痛点&#xff1a; 1.Http请求基于请求与响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求达到服务器端…

C# WinForm —— 19 PictureBox 介绍

1. 简介 PictureBox 主要用于显示图像&#xff0c;也可以给它注册单击事件&#xff0c;来把它变成一个按钮 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 pixB 开头BackColor控件的背景色BackgroundImage控件的背景图像BorderStylePictur…

开放式耳机什么品牌最好?2024五款新晋爆款产品推荐!

​如今的耳机市场天下三分&#xff0c;有线入耳式耳机、蓝牙无线入耳式耳机以及开放式耳机&#xff0c;传统的有线入耳式耳机戴着不稳就算了&#xff0c;线很容易揉成一团&#xff0c;看着就头大&#xff1b;无线入耳式的耳机&#xff0c;同样面临着戴着不稳的问题&#xff0c;…

如何在群晖NAS中开启FTP并实现使用公网地址远程访问传输文件

文章目录 1. 群晖安装Cpolar2. 创建FTP公网地址3. 开启群晖FTP服务4. 群晖FTP远程连接5. 固定FTP公网地址6. 固定FTP地址连接 本文主要介绍如何在群晖NAS中开启FTP服务并结合cpolar内网穿透工具&#xff0c;实现使用固定公网地址远程访问群晖FTP服务实现文件上传下载。 Cpolar内…

Nginx内网环境开启https

文章目录 前言一、open-ssl1. 验证2. 安装3.生成ssl证书 一、nginx1. 验证支持模块2. 安装必要模块2.1 重新编译nginx2.2 替换原文件 3. 配置https 总结 前言 nginx开启https前提&#xff1a; 服务器支持open-sslnginx 包含--with-http_ssl_module --with-stream --with-stre…

JavaScript原理篇——Promise原理及笔试题实战演练

Promise 是 JavaScript 中用于处理异步操作的对象&#xff0c;它代表了一个可能还没有完成的操作的最终完成或失败&#xff0c;以及其结果值。Promise 对象有三种状态&#xff1a; Pending&#xff08;进行中&#xff09;&#xff1a;初始状态&#xff0c;既不是成功&#xff0…

前端js面试题--从字符串中删除删除注释代码

问题&#xff1a;从字符串中删除删除注释代码 描述&#xff1a; solution(weex,rex # and react\nflutter\nnative ssss !hybrid app, [#, !]) 写一个solution函数清除后面参数数组里面的字符串 打印效果 代码1 思路&#xff1a; 将字符全凡是有去掉标志符号的全部添加\n…

flutter 使用Scrollbar 时出现 滚动条不置顶问题

Flutter 使用 CupertinoScrollbar 、Scrollbar 与 ListView.builder 结合使用时&#xff0c; 当把 ListView.builder 边距设置为 padding: const EdgeInsets.all(0) 的时候&#xff0c; Scrollbar 的滚动条不置顶。 如图&#xff1a;右侧边上的滚动条 解决方法&#xff1a; …

什么是.faust勒索病毒?应该如何防御?

faust勒索病毒详细介绍 faust勒索病毒是一种新型的勒索软件&#xff0c;最早出现在2018年。该病毒通过加密计算机系统中的文件并要求支付赎金来解锁文件&#xff0c;从而获取经济利益。与传统的勒索软件相比&#xff0c;faust勒索病毒采用了更加先进的加密算法和隐藏技术&#…

浅析视频汇聚EasyCVR视频融合云平台在机场安防智能检测建设中的应用

一、背景 机场作为国家交通枢纽和对外开放的窗口&#xff0c;其安全运行直接关系到乘客的生命安全、国家形象以及社会经济稳定。随着全球航空业的快速发展和人们出行需求的持续增长&#xff0c;机场作为重要的交通枢纽&#xff0c;其客流量和货运量均呈现出快速增长的态势。然而…

【鸿蒙+全国产瑞芯微】智慧楼宇解决方案 | 如何实现多场景下智慧化、精细化楼宇管理?

随着数字化、智能化与工作生活的联结日渐紧密&#xff0c;聚焦人性化服务&#xff0c;以数字和科技匹配多重需求&#xff0c;加速商业楼宇智能化转型的脚步&#xff0c;逐步形成智慧楼宇产品矩阵。 方案亮点 01/数字标牌——形象展示 企业文化宣传、公告通知等 播放内容统一远…

实时追踪维修进度,报修管理小程序让你省心又省力!

随着生活、工作节奏的日益加快&#xff0c;日常的售后报修、故障报修处理流程给我们带来种种困扰。我们都知道大多数企业、个人用户还在使用传统报修方式&#xff0c;如电话报修、纸质报修单等方式&#xff0c;不仅效率低下&#xff0c;而且难以追踪维修进度&#xff0c;给我们…

C# 使用Queue高效检索树行数据符合条件的数据,并返回完整树形数据示例

最近有项目需要加载大型树数据&#xff0c;数据大概3W条 后端使用C# NET6 前端使用Vue3 elementuiplus 虚拟tree 》解决大型树数据加载 遇到的问题是后端在检索数据时&#xff0c;要返回匹配数据的完整树目录 1.因为单条数据没有存放完整路径&#xff0c;需要通过父级ID逐…

第六节笔记及作业----Lagent AgentLego 智能体应用搭建

关于 Agent 的相关理论 大语言模型存在一些局限性&#xff0c;比如会出现幻觉问题、有时效性问题以及可靠性问题。智能体的定义是具备感知、决策和行动能力的实体。智能体主要由感知部分、大脑部分和动作部分组成。智能体有多种类型&#xff0c;如 ReAct 类型&#xff08;侧重…

事务性邮件邮箱API发送邮件的要点有哪些?

事务性邮件邮箱API发送邮件怎么使用&#xff1f;API的使用方式&#xff1f; 使用邮箱API进行事务性邮件的发送&#xff0c;不仅能确保信息的准确传达&#xff0c;还能大大提高工作效率。那么&#xff0c;在使用事务性邮件邮箱API发送邮件时&#xff0c;我们应该注意哪些要点呢…

triton之gemm

一 原理 如果不采用group gemm的话,采用单流执行,则具体的硬件执行调度如下所示: gemm0,gemm1,gemm2同时分配任务给sm做 第一轮:gemm0、gemm1和gemm2的0-4分给4个sm去做,都计算完成 第二轮:gemm0在上一轮已经计算完毕,gemm1和gemm2的45分给sm0,sm1去做,在这一轮…

RelationMap图谱--VUE,真实项目提供mock数据

RelationMap官网&#xff1a; 在线配置官网&#xff08;可以把数据放进去&#xff0c;直接看效果&#xff09; VUE2 效果&#xff1a;左侧列表栏&#xff0c;点击右侧显示对应的图谱 代码&#xff1a;按照代码直接贴过去&#xff0c;直接出效果 relationMap/index.vue <te…