C++-map和set

本期我们来学习map和set

目录

关联式容器

键值对 

pair

树形结构的关联式容器

set

multiset

map

multimap


关联式容器

我们已经接触过 STL 中的部分容器,比如: vector list deque 、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?
关联式容器 也是用来存储数据的,与序列式容器不同的是,其 里面存储的是 <key, value> 结构的 键值对,在数据检索时比序列式容器效率更高

键值对 

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 key value key 表键值, value 表示与 key 对应的信息 。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

SGI-STL中关于键值对的定义:

pair

template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};

树形结构的关联式容器

根据应用场景的不桶, STL 总共实现了两种不同结构的管理式容器:树型结构与哈希结构。 树型结 构的关联式容器主要有四种: map set multimap multiset 。这四种容器的共同点是:使用平衡搜索树( 即红黑树 ) 作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器。

set

1. set 是按照一定次序存储元素的容器
2. set 中,元素的 value 也标识它 (value 就是 key ,类型为 T) ,并且每个 value 必须是唯一的。
set 中的元素不能在容器中修改 ( 元素总是 const) ,但是可以从容器中插入或删除它们。
3. 在内部, set 中的元素总是按照其内部比较对象 ( 类型比较 ) 所指示的特定严格弱排序准则进行排序。
4. set 容器通过 key 访问单个元素的速度通常比 unordered_set 容器慢,但它们允许根据顺序对
子集进行直接迭代。
5. set 在底层是用二叉搜索树 ( 红黑树 ) 实现的。
注意:
1. map/multimap 不同, map/multimap 中存储的是真正的键值对 <key, value> set 中只放
value ,但在底层实际存放的是由 <value, value> 构成的键值对。
2. set 中插入元素时,只需要插入 value 即可,不需要构造键值对。
3. set 中的元素不可以重复 ( 因此可以使用 set 进行去重 )
4. 使用 set 的迭代器遍历 set 中的元素,可以得到有序序列
5. set 中的元素默认按照小于来比较
6. set 中查找某个元素,时间复杂度为: $log_2 n$
7. set 中的元素不允许修改 ( 为什么 ?)
8. set 中的底层使用二叉搜索树 ( 红黑树 ) 来实现

 我们发现,set的模板参数比我们之前学的多了一个compare,这是仿函数,支持key比较大小的

我们来看它的构造,有拷贝构造,默认构造以及迭代器区间初始化

set的迭代器是双向迭代器

这里的key_type和value_type都是T,这里我们后面会讲

下面我们简单使用一下

使用没什么问题,我们在这里还发现一个问题,它的输出结果是有序的,因为它走的是中序遍历

而且还会去重,去重的原理是如果一个值已经有了,那就不插入

也可以使用范围for遍历

erase支持迭代器位置,值已经迭代器区间

我们根据情况选择即可

如果直接删除值,值不存在没什么问题,但如果用find先查找的话,这里就会报错,因为pos不存在

我们再看看这两个find有什么区别,一个是set自己的find,另一个是算法库里的 

set自己的find最多查找高度次,时间复杂度是O(longN),而算法库的find是暴力查找,是O(N),所以我们最好不要用库里面的

还有一个count,这个set这里基本用不到

和find差不多,我们传一个元素,如果在返回1,不在就返回0

find是返回迭代器,而count是返回1或者0 

还有这三个函数,是寻找边界的特殊情况用的,我们来看看例子就明白了

 比如我们查找30和60,itlow得到的就是30,而itup是比60大的,因为迭代器区间是左闭右开,这样就可以和迭代器适配,可以保证30到60之间删除(包括60)

 如果我们找35,得到的是40,lower_bound查找的是>=的值,upper_bound是>

 equal_range也是一样,会查找一个左闭右开的区间

multiset

我们再看这个容器,它用起来和set是一样的 

它和set的区别就是它允许有重复 

如果我们要删除所有的5,我们上面的equal_range就是这样使用的 ,count也是在这里使用,这里可以算出有多少个5,我们可以认为这两个接口就是专门为multiset设计的,set有这两个接口只是为了保持接口一致罢了

当有重复值时,find返回的是中序的第一个

equal_range返回的是>=,如果给的值不存在,返回的就是不存在的区间

map

1. map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
2. map 中,键值 key 通常用于排序和惟一地标识元素,而值 value 中存储与此键值 key 关联的
内容。键值 key 和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型
value_type 绑定在一起,为其取别名称为 pair:
typedef pair<const key, T> value_type;
3. 在内部, map 中的元素总是按照键值 key 进行比较排序的。
4. map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序
对元素进行直接迭代 ( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
5. map 支持下标访问符,即在 [] 中放入 key ,就可以找到与 key 对应的 value
6. map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))

map这里也有三个type,下面我们简单使用一下

我们先看insert 

 map是kv模型,所以使用起来非常麻烦,那么可不可以像我们以前那样直接传呢?答案是可以的

原因是有make_pair

就像这样,这里就是map的插入 

当然还可以更简洁一点,直接用{ }括起来,这是因为C++11支持多参数的构造函数隐式类型转换,也就是说这种写法在C++98是不能用的

接着我们来遍历,但是按照我们之前写的遍历,这里就出错了,原因是pair不支持流插入和流提取

 

那为什么这里不像我们写的那样直接用key和value,而要使用一个pair?

原因是operator*返回的话不方便,如果直接使用,C++是不支持返回两个值的,所以设计了一个pair结构

所以得这样写

 如果觉得上面的写法麻烦还可以用->

大概就是这样 

我们之前也说过,如果不是编译器优化,这里是要有两个箭头的 ,第一个是运算符重载,第二个是访问

也可以用范围for

first是不允许修改的,second可以修改 

如果key相同,value不同,是不能插入了,key相同时不插入,不覆盖 ,也就是插入过程中只比较key,value无所谓

erase也是一样,只看key在不在

 

下面我们来看看[ ] 

我们来看这个统计次数,我们以后就可以直接用map

 

而且代码可以优化,我们可以使用 [ ]  

map的[ ] 不是常规的,而是给key,返回对应的value

后面的++我们懂,但是水果第一次出现是怎么回事呢?

 它返回了这么个东西,借助了insert的返回值

 我们可以看到insert的返回值是一个pair

 大致翻译一下:这里返回一个pair,这个pair的first被设置为迭代器,要么指向新插入的元素,要么指向和key相等的元素,second被设计为true,如果key在里面返回false

也就是说,key已经在树里面,返回pair<树里面key所在节点的iterator,false>,如果key不在树里面,返回pair<新插入key所在节点的iterator,true>

如果我们自己设计就是这样,ret里除了key,另一个是匿名对象,根据value的变化而变化,如果key不在树里面, 那就插入成功,如果value是int那就是0,如果是string就是空的string,如果插入失败,也没有影响,因为insert只看key,而return时,first是迭代器,有了迭代器我们就可以取到second

 我们结合起来理解一下,水果第一次出现时,insert,key是水果,value是int,int的匿名对象缺省值是0,然后返回这个次数,++一下就变成了1,如果有的话,那就插入失败,再返回次数,++次数就可以计数了

我们来一步一步看这个

 我们经过dict["sort"]时是不影响的

这里是可以读的,也就是说,这里是查找+读

 经过dict["map"]时,监视窗口多了一个map,value是空的,和我们前面看到的一样,[ ] 的本质是insert

接着我们修改了value(空的value)

 这次我们修改了insert的value

最后一个就是插入+修改了(修改空的value)

 [ ] 的功能非常多,我们用的时候也就要小心一点

multimap

这个也没啥好说的,对于map就和multiset对于set似的,就是可以有重复的key

不同的地方在于multimap没有提供operator[ ],所以insert也不一样了,不提供pair了,插入永远成功,其他功能一样

以上即为本期全部内容,希望大家可以有所收获

如有错误,还请指正

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Ubuntu搭建MQTT Broker及面板+发布消息、订阅主题】

Ubuntu搭建MQTT Broker及面板发布消息、订阅主题 配置curl数据源 curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash开始安装 sudo apt-get install emqx启动 sudo emqx start使用面板 根据自己的服务器是否开始了防火墙放行端口&#xff08;1808…

YOLO目标检测——火焰烟雾数据集+已标注VOC和YOLO格式标签下载分享

实际项目应用&#xff1a;火灾预警系统、智能监控系统、工业安全管理、森林火灾监测以及城市规划和消防设计等应用场景中具有广泛的应用潜力&#xff0c;可以提高火灾检测的准确性和效率&#xff0c;保障人员和财产的安全。数据集说明&#xff1a;YOLO火焰目标检测数据集&#…

合宙Air724UG LuatOS-Air LVGL API控件-截屏(Screenshots)

截屏&#xff08;Screenshots&#xff09; 分 享导出pdf 截屏功能&#xff0c;core版本号要>3211 示例代码 -- 创建图片控件img lvgl.img_create(lvgl.scr_act(), nil)-- 设置图片显示的图像lvgl.img_set_src(img, "/lua/test.png")-- 图片居中lvgl.obj_align(…

Kafka入门与安装

为什么要用消息中间件&#xff1f; 异步处理 场景说明&#xff1a;用户注册后&#xff0c;需要发注册邮件和注册短信。传统的做法有两种1.串行的方式&#xff1b;2.并行方式。 串行方式&#xff1a;将注册信息写入数据库成功后&#xff0c;发送注册邮件&#xff0c;再发送注…

elementUI时间选择器

<template>//月选择器//:clearable"false" 去掉<div class"monthCard"><el-date-picker:clearable"false"v-model"monthValue"type"month"placeholder"选择月"change"handleChangeMonth($eve…

vue3笔记

vue3笔记 vue3官网 尚硅谷视频 黑马视频 ## vue3的main.js 1.vue3 import { createApp } from vue // 引入createApp方法 import App from ./App.vue // 引入App根组件 createApp(App).mount(#app) // 创建一个 Vue 实例&#xff0c;并将其挂载到 id 为 "app" 的 …

静态工厂模式,抽象工厂模式,建造者模式

静态工厂模式 ublic class FruitFactory {public static Fruit getFruit(String name) {Fruit fnull;switch (name){case "APPLE":{fnew Apple();}case "BANANA":{fnew Banana();}default :{System.out.println("Unknown Fruit");}}return f;} …

RabbitMQ 知识点解读

1、AMQP 协议 1.1、AMQP 生产者的流转过程 当客户端与Broker 建立连接的时候&#xff0c;会调用factory .newConnection 方法&#xff0c;这个方法会进一步封装成Protocol Header 0-9-1 的报文头发送给Broker &#xff0c;以此通知Broker 本次交互采用的是AMQPO-9-1 协议&…

算法:数组中的最大差值---“打擂台法“

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132737088 欢迎各位大佬指点、三连 1、题目&#xff1a; 给定一个整数数组 nums&#xff0c;找出给定数组中两个数字之间的最大差值。要求&#xff0c;第二个数字必须大于第一个数字。 2、分析特…

【Docker】容器化应用程序的配置管理策略与实践

一、引言 1.1 Docker的背景和优势 Docker是一种开源的容器化平台&#xff0c;简化应用程序的打包、交付和运行过程。基于Linux容器技术&#xff0c;通过提供一个轻量级、可移植和自包含的容器来实现应用程序的隔离和部署。 在传统的应用程序开发和部署中&#xff0c;往往需要…

Vue2项目练手——通用后台管理项目第七节

Vue2项目练手——通用后台管理项目 用户管理分页使用的组件Users.vuemock.js 关键字搜索区Users.vue 权限管理登录页面样式修改Login.vue 登录权限使用token对用户鉴&#xff0c;使用cookie对当前信息保存&#xff08;类似localstorage&#xff09;Login.vuerouter/index.js 登…

pyqt5设置背景图片

PyQt5设置背景图片 1、打开QTDesigner 创建一个UI&#xff0c;camera.ui。 2、创建一个pictures.qrc文件 在ui文件同级目录下先创建一个pictures.txt&#xff0c;填写内容&#xff1a; <RCC><qresource prefix"media"><file>1.jpg</file>…

【Python】conda虚拟环境下使用pyinstaller打包程序为exe

文章目录 一、为什么要用conda虚拟环境二、pyinstaller用法2.1 安装 PyInstaller2.2 基本用法打包一个 Python 脚本2.21 打包一个 Python 项目2.22 打包选项 2.3 打包依赖项2.31 导出依赖项列表2.32 配置依赖项 2.4 自定义打包选项2.5 打包完成后的文件2.6 注意事项 三、打包示…

解决外接显示器后Edge浏览器地址栏等变得很大的问题

解决外接显示器后Edge浏览器地址栏等变得很大的问题 edge设置里外观——触控模式&#xff0c;把触控模式关了

Kafka详解

目录 一、消息系统 1、点对点的消息系统 2、发布-订阅消息系统 二、Apache Kafka 简介 三、Apache Kafka基本原理 3.1 分布式和分区&#xff08;distributed、partitioned&#xff09; 3.2 副本&#xff08;replicated &#xff09; 3.3 整体数据流程 3.4 消息传送机制…

高忆管理:六连板捷荣技术或难扛“华为概念股”大旗

在本钱商场上名不见经传的捷荣技术&#xff08;002855.SZ&#xff09;正扛起“华为概念股”大旗。 9月6日&#xff0c;捷荣技术已拿下第六个连续涨停板&#xff0c;短短七个生意日&#xff0c;股价累积涨幅逾越90%。公司已连发两份股票生意异动公告。 是炒作&#xff0c;还是…

kubernetes常见面试问题详解

在面试的时候&#xff0c;面试官常常会问一些问题&#xff1a; k8s是什么&#xff1f;有什么用?k8s由哪些组件组成&#xff1f;pod的启动流程&#xff1f;k8s里有哪些控制器&#xff1f;k8s的调度器里有哪些调度算法&#xff1f;pod和pod之间的通信过程&#xff1f;外面用户访…

3D视觉测量:形位公差 平面度测量(附源码)

文章目录 0. 测试效果1. 基本内容2. 实现方法3. 代码实现4. 参考文章目录:形位公差测量关键内容:通过视觉方法实现GD&T中的平面度计算0. 测试效果 1. 基本内容 平面度是一个表达平面平整程度的度量指标,它描述了一个表面与一个理想平面之间的偏差程度。在工程和制造领域…

C++之红黑树

红黑树 红黑树的概念红黑树的性质红黑树结点的定义红黑树的插入红黑树的验证红黑树与AVL树的比较 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上…

[SUCTF2019]SignIn 题解

是一个64位的文件 使用了RSA加密算法 N是103461035900816914121390101299049044413950405173712170434161686539878160984549 使用在线网站分离得到p&#xff0c;q 然后编写脚本进行解密 import gmpy2 import binasciip 282164587459512124844245113950593348271 q 366669…