面试之快速学习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…...

博客系统之功能测试
博客系统共有:用户登录功能、发布博客功能、查看文章详情功能、查看文章列表功能、删除文章功能、退出功能 1.登录功能: 1.1测试对象:用户登录 1.2测试用例 方法:判定表 用例 编号 操作步骤预期结果实际结果截图1 1.用户名正确…...

CJS和 ES6 的语法区别
CommonJS 使用 module.exports 导出模块。ES6 使用 export 导出模块。 示例代码: CommonJS(CJS)模块的导出: // 导出模块 module.exports {foo: bar,baz: function() {return qux;} }; ES6 模块的导出: // 导出模…...

ArcGIS Pro如何制作不规则形状图例
在默认的情况下,ArcGIS Pro生成的图例是标准的点、直线和矩形的,对于湖泊等要素而言,这样的表示方式不够直观,我们可以将其优化一下,制作不规则的线和面来代替原有图例,这里为大家介绍一下制作方法…...

微软Win11 Dev预览版Build23526发布
近日,微软Win11 Dev预览版Build23526发布,修复了不少问题。牛比如斯Microsoft,也有这么多bug,所以你写再多bug也不作为奇啊。 主要更新问题 [开始菜单] 修复了在高对比度主题下,打开开始菜单中的“所有应…...

【NEW】视频云存储EasyCVR平台H.265转码配置增加分辨率设置
关于视频分析EasyCVR视频汇聚平台的转码功能,我们在此前的文章中也介绍过不少,感兴趣的用户可以翻阅往期的文章进行了解。 安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各…...

【数据结构】如何用队列实现栈?图文详解(LeetCode)
LeetCode链接:225. 用队列实现栈 - 力扣(LeetCode) 本文默认读者已经掌握栈与队列的基本知识 或者先看我的另一篇博客:【数据结构】栈与队列_字节连结的博客-CSDN博客 做题思路 由于我们使用的是C语言,不能直接使用队…...

Linux 虚拟机Ubuntu22.04版本通过远程连接连接不上,输入ifconfig只能看到127.0.0.1的解决办法
之前给虚拟机配置静态IP之后,可以直接通过主机Vscode远程连接。但是前一段时间把主机的TCP/IPV4静态IP设置了一下之后,再连接虚拟机就连不上了,于是参考解决虚拟机不能上网ifconfig只显示127.0.0.1的问题,又可以连接上了ÿ…...

C语言刷题训练DAY.9
1.线段图案 解题思路: 这里非常简单,我们只需要用一个循环控制打印即可。 解题代码: #include<stdio.h> int main() {int n 0;while ((scanf("%d", &n)) ! EOF){int i 0;for (i 0; i < n; i){printf("*&…...

CTFHub php://input
1.首先看代码: 这里其实就应该想到的是php://伪协议: php://filter、php://input、php://filter用于读取源码 php://input用于执行php代码 2.其次,判断使用php://input伪协议 而执行php://input伪协议条件是allow_url_include是On 可以先利用…...

React Native expo项目修改应用程序名称
https://expo.dev/accounts/xutongbao/projects npm install --global eas-cli && \eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 app.config.js: export default {name: 学习,slug: learn-gpt,owner: x…...