面试之快速学习STL-容器适配器

news2024/11/17 11:38:44

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容器适配器详解

  1. priority_queue 容器适配器模拟的也是队列这种存储结构,即使用此容器适配器存储元素只能“从一端进(称为队尾),从另一端出(称为队头)”,且每次只能访问 priority_queue 中位于队头的元素。
  2. 但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是“First in,Largest out”原则。直白的翻译,指的就是先进队列的元素并不一定先出队列,而是优先级最大的元素最先出队列
  3. priority_queue 容器适配器中存储的元素,优先级是如何评定的呢?很简单,每个 priority_queue 容器适配器在创建时,都制定了一种排序规则。根据此规则,该容器适配器中存储的元素就有了优先级高低之分。
  4. 假设当前有一个 priority_queue 容器适配器,其制定的排序规则是按照元素值从大到小进行排序。根据此规则,自然是 priority_queue 中值最大的元素的优先级最高。
  5. priority_queue 容器适配器为了保证每次从队头移除的都是当前优先级最高的元素,每当有新元素进入,它都会根据既定的排序规则找到优先级最高的元素,并将其移动到队列的队头;同样,当 priority_queue 从队头移除出一个元素之后,它也会再找到当前优先级最高的元素,并将其移动到队头。
template <typename T, 
		typename Container=std::vector<T>, 
		typename Compare=std::less<T> >
class priority_queue {
//......
}
  1. 可以看到,priority_queue 容器适配器模板类最多可以传入 3 个参数,它们各自的含义如下:
  • typename T:指定存储元素的具体类型;
  • typename Container:指定 priority_queue 底层使用的基础容器,默认使用 vector 容器。
  • typename Compare:指定容器中评定元素优先级所遵循的排序规则,默认使用std::less 按照元素值从大到小进行排序,还可以使用std::greater按照元素值从小到大排序,但更多情况下是使用自定义的排序规则。
  1. 作为 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
  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()); 
  1. 注意不支持
std::priority_queue<int, std::vector<int>, std::greater<int>> pq1{2,3,4,1,5};

在这里插入图片描述

  1. 和 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();
    }
    /*
     1
     2
     3
     4
     5
     */

自定义比较函数-仿函数

  1. greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数,其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了),所以调用的是fun()?
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
  1. 如果自己想模拟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();
    }
    /*
     1
     2
     3
     4
     5
     */

自定义比较函数-重载运算符

  1. 如果是个自定义类,也可以在自定义类里面自己重载运算符
    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();
    }
    /*
     5
     4
     3
     2
     1
     */
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();
    }
    /*
     5
     4
     3
     2
     1
     */

补充一个比较有意思的点

前面提到的自定义比较函数-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的底层实现

本来准备单独用一章写,但是看了一下,其实底层实现就是一个堆,特点:

  1. heap是一颗完全二叉树:整颗树除了最底层,都是填满的,而且底层节点从左到右不存在空隙。
    在这里插入图片描述
  2. 两个操作
    • push_heap: 因为要满足完全二叉树的性质,需要将新节点放置在底层节点的最后面,也就是vector的end(),然后执行上溯操作:只要父节点比自己小,就不断调换自己和父节点的位置。
      在这里插入图片描述
    • pop_heap: 将heap的最大元素取走,也就是将根节点取走,那根据完全二叉树的性质,得把底层最后面的元素换到根节点。然后不断执行下溯操作:将自己和两个子节点中,较大的那个对调。

做完下溯操作后,可能还需做一次上溯操作

在这里插入图片描述
参考: https://blog.csdn.net/youaremyalllove/article/details/124043310

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

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

相关文章

VS 运行编译通过,但代码下方 标红波浪线 问题

解决办法一&#xff1a;重新扫描 一次 解决方案&#xff0c; 就会去掉红线 方法2&#xff1a; VS 运行编译通过&#xff0c;但代码标红波浪问题解决办法_vs代码下面有波浪线_Start_Or_Out的博客-CSDN博客

算法与数据结构(五)--树与二叉查找树

符号表的增删查操作&#xff0c;随着元素个数N的增多&#xff0c;其耗时也是线性增多的&#xff0c;时间复杂度都是O(n)&#xff0c;为了提高运算效率&#xff0c;我们学习树这种数据结构。 目录 一.树的基本定义 二.树的相关术语 三.二叉树的基本定义 四.二叉树的链表实现…

Linux 进程间通信——消息队列

一、消息队列的原理 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型&#xff0c;接收进程可以独立接收含有不同类型值得数据库。 消息实际上是一个数据块&#xff0c;这个数据块是一个结构体&#xff0c;结构体由自己命名。消…

跨境电商平台(例如阿里巴巴、虾皮)的商品数据如何收集?

跨境电商是指通过互联网&#xff0c;以跨越国家或地区边界的方式进行电子商务交易的商业行为。传统的电子商务通常是在同一国家或地区内进行&#xff0c;而跨境电商则侧重于跨国贸易。跨境电商通过在线平台&#xff08;如阿里巴巴、亚马逊等&#xff09;或第三方服务商&#xf…

智慧工地平台工地人员管理系统 可视化大数据智能云平台源码

智慧工地概述&#xff1a; 智慧工地管理平台是以物联网、移动互联网技术为基础&#xff0c;充分应用大数据、人工智能、移动通讯、云计算等信息技术&#xff0c;利用前端信息采通过人机交互、感知、决策、执行和反馈等&#xff0c;实现对工程项目內人员、车辆、安全、设备、材…

Spark 为什么比 MapReduce 快100倍?

文章目录 1. 内存计算与磁盘刷写1.1 MapReduce 的 Shuffle 需要频繁 IO1.2 Spark 计算走 IO 少 2. 进程和线程2.1 基于进程的 MapReduce2.2 基于线程的 Spark2.3 基于进程 VS 基于线程 3. 持久化缓存机制4. 数据格式和序列化 通常我们认为 Spark 引擎是基于内存进行计算&#x…

【STL】-- 知识总结

目录 STL六大组件介绍 容器 序列式容器 vector list 知识点考察 关联式容器 map/set set介绍 set常用接口 map介绍 map常用接口 底层结构&#xff1a;红黑树 unordered_map/set unordered_map/set介绍 底层结构&#xff1a;哈希表 知识考察 适配器 stack qu…

【ESP系列】ESP01S官方MQTT案例实验

前言 偶然发现安信可官网有ESP01S和STM32连接TCP和MQTT的案例。弄了一两天&#xff0c;把我使用的流程在这里记录下。MQTT的固件一定要烧录进去&#xff0c;默认固件是没有MQTT相关的AT指令的。 环境 Keli5&#xff0c;STM32F103C8T6 官方Keil工程链接&#xff1a;ESP8266的S…

虫情测报灯

在农业生产过程中&#xff0c;农作物的虫害问题永远都是放在首位的。随着现代生活科技的发展和社会进步&#xff0c;人们对物质也有了新的要求。伴随农作物品种的增加&#xff0c;农药和化肥的使用也在导致农业虫害问题日益加剧&#xff0c;在这种不良的耕作状态下&#xff0c;…

JSP介绍

目录 获取表单提交的数据 请求对象 request response 在请求中存取属性 转发与重定向 session cookie pageContext对象 jsp 动作标签 JSP内置对象是什么: 在jsp开发中会频繁使用到一些对象,如ServletContext HttpSession PageContext等.如果每次我们在jsp页面中需要使…

JavaWeb 速通Listener

目录 一、Listener快速入门 1.Listener简介 : 2.Java事件处理机制 : 二、ServletContextListener 1.作用 : 2.相关方法 : 3.应用实例 : 三、ServletContextAttributeListener 1.作用 : 2.相关方法 : 3.应用实例 : 四、HttpSessionListener 1.作用 : 2.相关方法 :…

KeilMDk软仿真设置_STM32F03C8

1、KeilMDK软仿真的价值 (1)在没有硬件的情况下进行程序的编写调试。 (2)避免频繁的下载程序&#xff0c;延长单片机Flash寿命。 2、软仿真配置。 (1)打开Keil工程。 (2)点击“Options for Target ***”&#xff0c;如下图所示。 (3)点击“Debug”。 (4)进行如下配置。 U…

无涯教程-TensorFlow - XOR实现

在本章中&#xff0c;无涯教程将学习使用TensorFlow的XOR实现&#xff0c;在TensorFlow中开始XOR实施之前&#xff0c;看一下XOR表值。这将帮助了解加密和解密过程。 A B A XOR B 0 0 0 0 1 1 1 0 1 1 1 0 XOR密码加密方法基本上用于加密&#xff0c;即通过生成与适当密钥匹配…

科技大厂GenAI最新动态一览!AI创意字终极全攻略;一文入门LLM应用开发框架LangChain;Llama初学者指南 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 使用浏览器插件 immersive translate&#xff0c;将外语书翻译成双语对照版 immersive translate 是一款非常好用的浏览器翻译插件。今…

idea2023 springboot2.7.5+mybatisplus3.5.2+jsp 初学单表增删改查

创建项目 修改pom.xml 为2.7.5 引入mybatisplus 2.1 修改pom.xml <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!--mysq…

XSS攻击是什么?它有哪些类型?

xss攻击是什么&#xff1f; XSS全称是Cross Site Scripting即跨站脚本&#xff0c;当目标网站目标用户浏览器渲染HTML文档的过程中&#xff0c;出现了不被预期的脚本指令并执行时&#xff0c;XSS就发生了。 作为一种HTML注入攻击&#xff0c;XSS攻击的核心思想就是在HTML页面中…

git错误记录

露id没有影响&#xff0c;搞得微软不知道我ip一样 git fatal: 拒绝合并无关的历史的错误解决(亲测有效)

使用Pandas处理Excel文件

Excel工作表是非常本能和用户友好的&#xff0c;这使得它们非常适合操作大型数据集&#xff0c;即使是技术人员也不例外。如果您正在寻找学习使用Python在Excel文件中操作和自动化内容的地方&#xff0c;请不要再找了。你来对地方了。 在本文中&#xff0c;您将学习如何使用Pan…

ansible(1)-- 部署ansible连接被控端

目录 一、部署ansible 1.1 安装 1.2 测试连接 192.168.136.55 ansible 192.168.136.56被控端 一、部署ansible 1.1 安装 zabbix-s只是主机名&#xff0c;不用在意&#xff0c;更好该主机也安装了zabbix&#xff0c;不好更改。 下载阿里云epel源 #安装阿里云的epel源&#…

33.Netty源码之读写数据

highlight: arduino-light 写数据 写数据的三种方式 md 快递场景(包裹) Netty 写数据(数据) 揽收到仓库 write&#xff1a;写到一个 buffer 从仓库发货 flush: 把 buffer 里的数据发送出去 揽收到仓库并立马发货 (加急件) writeAndFlush&#xff1a;写到 buffer&#xff0c;立马…