面试之快速学习STL-容器适配器
1. 容器适配器
简单的理解容器适配器,其就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。
注意:默认使用的基础容器不代表一定只能用它,比如queue可以用deque,list。
如果你希望你的queue是list那么可以如下创建:
std::queue<int , std::list<int>> q;
可以直接通过 queue 容器适配器来初始化另一个 queue 容器适配器,只要它们存储的元素类型以及底层采用的基础容器类型相同即可。例如:
std::deque<int> values{1,2,3};
std::queue<int> my_queue1(values);
std::queue<int> my_queue(my_queue1);
//或者使用
//std::queue<int> my_queue = my_queue1;
2. priority_queue容器适配器详解
- priority_queue 容器适配器模拟的也是队列这种存储结构,即使用此容器适配器存储元素只能“从一端进(称为队尾),从另一端出(称为队头)”,且每次只能访问 priority_queue 中位于队头的元素。
- 但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是“First in,Largest out”原则。直白的翻译,指的就是先进队列的元素并不一定先出队列,而是优先级最大的元素最先出队列。
- priority_queue 容器适配器中存储的元素,优先级是如何评定的呢?很简单,每个 priority_queue 容器适配器在创建时,都制定了一种排序规则。根据此规则,该容器适配器中存储的元素就有了优先级高低之分。
- 假设当前有一个 priority_queue 容器适配器,其制定的排序规则是按照元素值从大到小进行排序。根据此规则,自然是 priority_queue 中值最大的元素的优先级最高。
- priority_queue 容器适配器为了保证每次从队头移除的都是当前优先级最高的元素,每当有新元素进入,它都会根据既定的排序规则找到优先级最高的元素,并将其移动到队列的队头;同样,当 priority_queue 从队头移除出一个元素之后,它也会再找到当前优先级最高的元素,并将其移动到队头。
template <typename T, typename Container=std::vector<T>, typename Compare=std::less<T> >
class priority_queue {
//......
}
- 可以看到,priority_queue 容器适配器模板类最多可以传入 3 个参数,它们各自的含义如下:
- typename T:指定存储元素的具体类型;
- typename Container:指定 priority_queue 底层使用的基础容器,默认使用 vector 容器。
- typename Compare:指定容器中评定元素优先级所遵循的排序规则,默认使用std::less 按照元素值从大到小进行排序,还可以使用std::greater按照元素值从小到大排序,但更多情况下是使用自定义的排序规则。
- 作为 priority_queue 容器适配器的底层容器,其必须包含 empty()、size()、front()、push_back()、pop_back() 这几个成员函数,STL 序列式容器中只有 vector 和 deque 容器符合条件。
创建priority_queue
//以使用普通数组或其它容器中指定范围内的数据,对 priority_queue 容器适配器进行初始化:
int values[]{4,1,3,2};
std::priority_queue<int> copy_values(values, values+4); // 4,3,2,1//使用序列式容器
std::vector<int> vec{1,5,3,4,2}
std::priority_queue<int> pq(vec.begin(), vec.end()); // 5,4,3,2,1
- 用来初始化的数组或容器中的数据不需要有序,priority_queue 会自动对它们进行排序。
//还可以手动指定 priority_queue 使用的底层容器以及排序规则,比如std::vector<int> vec{1,5,3,4,2};
std::priority_queue<int, std::vector<int>, std::greater<int>> pq(vec.begin(), vec.end());
- 注意不支持
std::priority_queue<int, std::vector<int>, std::greater<int>> pq1{2,3,4,1,5};
- 和 queue 一样,priority_queue 也没有迭代器,因此访问元素的唯一方式是遍历容器,通过不断移除访问过的元素,去访问下一个元素。
std::vector<int> vec1{1,5,3,4,2};std::priority_queue<int, std::vector<int>, std::greater<int>> pq(vec1.begin(), vec1.end());while (!pq.empty()) {std::cout<< pq.top()<<std::endl;pq.pop();}/*12345*/
自定义比较函数-仿函数
- greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数,其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了),所以调用的是fun()?
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
- 如果自己想模拟less和greater,那么使用的方法应该是这样:
std::priority_queue<int,std::vector<int>, myFun> pq3(vec1.begin(), vec1.end());while (!pq3.empty()) {std::cout<< pq3.top()<<std::endl;pq3.pop();}/*12345*/
自定义比较函数-重载运算符
- 如果是个自定义类,也可以在自定义类里面自己重载运算符
std::priority_queue<tmp1> qp2;tmp1 t1{2};tmp1 t11{3};tmp1 t111{1};tmp1 t1111{4};qp2.push(t1);qp2.push(t11);qp2.push(t111);qp2.push(t1111);while (!qp2.empty()) {std::cout<< qp2.top().x<<std::endl;qp2.pop();}/*54321*/
std::priority_queue<tmp1> qp2;
自定义比较函数-lambda
auto cmp = [](int a, int b) -> bool { return a < b;};std::priority_queue<int, std::vector<int>, decltype(cmp)> pq4(vec1.begin(), vec1.end(),cmp);while (!pq4.empty()) {std::cout<< pq4.top()<<std::endl;pq4.pop();}/*54321*/
补充一个比较有意思的点
前面提到的自定义比较函数-lambda, 其实传入的是一个函数指针,什么意思呢?
你可以这样写效果是一样的:
auto cmp = [](int a, int b)-> bool { return a < b; };std::priority_queue<int, std::vector<int>, std::function<bool(int,int)>> pq5(vec1.begin(), vec1.end(), cmp);while (!pq5.empty()) {std::cout<< pq5.top()<<std::endl;pq5.pop();}
但是你不可以这样写:
std::priority_queue<int, std::vector<int>, decltype(cmp(1,2))> pq4(vec1.begin(), vec1.end(),cmp);
//decltype(cmp(1,2))的到的是bool,而不是函数指针
小问题,好吧,是我理解的不够。
关于priority_queue的底层实现
本来准备单独用一章写,但是看了一下,其实底层实现就是一个堆,特点:
- heap是一颗完全二叉树:整颗树除了最底层,都是填满的,而且底层节点从左到右不存在空隙。
- 两个操作
- push_heap: 因为要满足完全二叉树的性质,需要将新节点放置在底层节点的最后面,也就是vector的end(),然后执行上溯操作:只要父节点比自己小,就不断调换自己和父节点的位置。
- pop_heap: 将heap的最大元素取走,也就是将根节点取走,那根据完全二叉树的性质,得把底层最后面的元素换到根节点。然后不断执行下溯操作:将自己和两个子节点中,较大的那个对调。
- push_heap: 因为要满足完全二叉树的性质,需要将新节点放置在底层节点的最后面,也就是vector的end(),然后执行上溯操作:只要父节点比自己小,就不断调换自己和父节点的位置。
做完下溯操作后,可能还需做一次上溯操作
参考: https://blog.csdn.net/youaremyalllove/article/details/124043310
相关文章:

面试之快速学习STL-容器适配器
1. 容器适配器 简单的理解容器适配器,其就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。 注意:默认使用的基础容器不代表一定只能用它,比如queue可以用deque,list。 如果你希望你的qu…...

性能比较 - Spring Boot 应用程序中的线程池与虚拟线程 (Project Loom)
本文比较了 Spring Boot 应用程序中的不同请求处理方法:ThreadPool、WebFlux、协程和虚拟线程 (Project Loom)。 在本文中,我们将简要描述并粗略比较可在 Spring Boot 应用程序中使用的各种请求处理方法的性能。 高效的请求处理在开发高性能后端…...
rust学习-打印结构体中的vec
write! 宏 将格式化后的数据写入到一个缓冲区(buffer),而不是直接打印到标准输出或文件中。 这个缓冲区可以是字符串,也可以是需要写入的文件的缓冲区。 write!(writer, format_string, expr1, expr2, ...);writer 参数是一个实…...

FPGA: RS译码仿真过程
FPGA: RS译码仿真过程 在上一篇中记录了在FPGA中利用RS编码IP核完成信道编码的仿真过程,这篇记录利用译码IP核进行RS解码的仿真过程,带有程序和结果。 1. 开始准备 在进行解码的过程时,同时利用上一篇中的MATLAB仿真程序和编码过程&#x…...
PostgreSQL 查询数据表、视图信息
--获得指定schema范围内的所有表和视图的列表,可指定一个排除表前缀模式with param as (select public,iit as schema_name,db2g% as exclude_pattern),base_info as (--获得所有基表select pg_namespace.nspname as schema_name, a.relname as tbl_name ,TBL as tb…...

手撕vector容器
一、vector容器的介绍 vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素,但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。 总结:vector是一个动态…...

PyMuPDF`库实现PDF旋转功能
本文介绍了一个简单的Python应用程序,用于将PDF文件转换为旋转90度的PDF文件。主要用于csdn网站中导出的博客pdf是横向的,看起来不是很方便,才想到用python编制一个将pdf从横向转为纵向的功能。 功能 该PDF转换工具具有以下功能:…...

微人事 登录问题完善
重启服务端的时候,发现前端页面会操作不了,这样后端session会失效,我们就需要让页面重新跳转到登录页 springsecurity配置类后端配置 前端拦截器进行拦截跳转...
【业务功能篇64】安装docker容器,在docker上安装mysql
docker教程: https://www.runoob.com/docker/docker-tutorial.html卸载docker 较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。 yum remove docker docker-client docker-client-latest docker-co…...
MyBatis的基本概念和核心组件
MyBatis的基本概念 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Pla…...
sql update执行返回0,能否判断数据不存在
答案:不能。 update执行返回0的情况 1、没有找到需要更新的数据,就是这条记录不存在 例如:where后面的条件是id0,那这条记录肯定是不存在的,返回结果是0 2、更新时的数据和要更新的数据完全一致时 例如:更…...

数据分析 | 调用Optuna库实现基于TPE的贝叶斯优化 | 以随机森林回归为例
1. Optuna库的优势 对比bayes_opt和hyperoptOptuna不仅可以衔接到PyTorch等深度学习框架上,还可以与sklearn-optimize结合使用,这也是我最喜欢的地方,Optuna因此特性可以被使用于各种各样的优化场景。 2. 导入必要的库及加载数据 用的是sklea…...

stm32单片机开关输入控制蜂鸣器参考代码(附PROTEUS电路图)
说明:这个buzzer的额定电压需要改为3V,否则不会叫,源代码几乎是完全一样的 //gpio.c文件 /* USER CODE BEGIN Header */ /********************************************************************************* file gpio.c* brief Thi…...

打印X型的图案
int main() {int n0;int i0;int j0;scanf("%d",&n);for(i0;i<n;i){for(j0;j<n;j){if(ij){printf("*");}else if((ij)n-1){printf("*");}elseprintf(" ");}printf("\n");}return 0; }...

不含数字的webshell绕过
异或操作原理 1.首先我们得了解一下异或操作的原理 在php中,异或操作是两个二进制数相同时,异或(相同)为0,不同为1 举个例子 A的ASCII值是65,对应的二进制值是0100 0001 的ASCII值是96,对应的二进制值是 0110 000…...

Mac上传项目源代码到GitHub的修改更新
Mac上传项目源代码到GitHub的修改更新 最近在学习把代码上传到github,不得不说,真的还挺方便 这是一个关于怎样更新项目代码的教程。 首先,在本地终端命令行打开至项目文件下第一步:查看当前的git仓库状态,可以使用git…...

Android6:片段和导航
创建项目Secret Message strings.xml <resources><string name"app_name">Secret Message</string><string name"welcome_text">Welcome to the Secret Message app!Use this app to encrypt a secret message.Click on the Star…...

ClickHouse AST is too big 报错问题处理记录
ClickHouse AST is too big 报错问题处理记录 问题描述问题分析解决方案1、修改系统配置2、修改业务逻辑 问题描述 项目中统计报表的查询出现 AST is too big 问题,报错信息如下: 问题分析 报错信息显示 AST is too big。 AST 表示查询语法树中的最大…...

DPDK系列之二十七DIDO
一、DIDO介绍 随着计算机技术发展,特别是应用技术的快速发展。应用场景对计算机的处理速度几乎已经到了疯狂的地步。说句大白话,再快的CPU也嫌慢。没办法,CPU和IO等技术基本目前都处在了瓶颈之处,大幅度提高,短时间内…...

《游戏编程模式》学习笔记(七)状态模式 State Pattern
状态模式的定义 允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。 举个例子 在书的示例里要求你写一个人物控制器,实现跳跃功能 直觉上来说,我们代码会这么写: void Heroine::handleInput(Input input…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...