C++:set和map的介绍

目录

关联式容器

键值对

set介绍: 

set的模板参数列表 

 set的双向迭代器:

insert的使用和set的特性:

 set的删除:

set的find: 

 lower_bound  、 upper_bound:

 multiset:

map介绍: 

pair< const Key , T> 

 和搜索二叉树的KV模型对比:

插入操作 

遍历操作 

注意事项:

使用范围for进行遍历:

 写法1:

写法2:

构造操作: 

operator[] 

operator[]的使用 

 operator[]的多种写法

查找操作

使用find进行查找

使用operator[]进行查找

count 

使用second排序操作 和 multimap

 

关联式容器

关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的 键值对,在数据检索时比序列式容器效率更高。

键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代 表键值,value表示与key对应的信息。

set介绍: 

1. set是按照一定次序存储元素的容器

2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。

3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。

4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代。  

5. set在底层是用二叉搜索树(红黑树)实现的。 

6.与map/multimap不同,map/multimap中存储的是真正的键值对,set中只放 value,但在底层实际存放的是由构成的键值对。

7. set中插入元素时,只需要插入value即可,不需要构造键值对。

8. set中的元素不可以重复(因此可以使用set进行去重)。

9. 使用set的迭代器遍历set中的元素,可以得到有序序列

10. set中的元素默认按照小于来比较

11. set中查找某个元素,时间复杂度为:$log_2 n$

12. set中的元素不允许修改(为什么?) 

set的模板参数列表 

  • T: set中存放元素的类型,实际在底层存储的键值对。
  • Compare:set中元素默认按照小于来比较,同时是一个仿函数
  • Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理  

 set的双向迭代器:

insert的使用和set的特性:

可以看出,当我们遍历set的迭代器时,遍历set内部的内容可以发现,set内部存储的形式是一个搜索二叉树,当遍历set时遍历出的结果是一个搜索二叉树中序遍历的结果,且set和搜索二叉树一样,具有去重功能和具有不允许修改内部数值的功能,因为修改内部的数据内容会导致set内部的存储结构失效。

 set的删除:

set的find: 

find是找到后返回该节点的迭代器

 lower_bound  、 upper_bound:

lower是找大于等于后面要找的值,而upper是要找大于要找的数值。

在这里因为lower找的是大于等于后面数值,然后返回那个数值节点的 迭代器,upper也是如此,这里upper是第一个比60大的数值的节点的迭代器,然后使用erase进行删除把者之间的数值进行删除,[30,70)不删除70

 multiset:

multiset其实是set的一种分支,和set相比,它不具备set的去重功能,但是内部的底层和set一样是一个搜索二叉树,但这个二叉树是允许重复的元素出现。 

这里如果按照搜索二叉树是不能有等于的,且大于在右小于在左边,这里就是左右都可以随便插入,当然相等的数值也不一定是连续的,因为底层还是树,所以需要寻找空位进行插入

但是如果要是find寻找重复的数值,那么multiset的find找的是中序排序后的第一个,也就是:查找X,查找到X的节点后,那么这个节点的左子树没有X节点,那么他就是中序的第一个X节点,如果左子树有X这个节点,那么接着往左子树方向继续查找X节点。 

map介绍: 

1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。

2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair: typedef pair value_type;

3. 在内部,map中的元素总是按照键值key进行比较排序的。

4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。

5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。  

  • key: 键值对中key的类型
  • T: 键值对中value的类型
  • Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比 较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户 自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
  • Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的 空间配置器
  • 注意:在使用map时,需要包含头文件。 

pair< const Key , T> 

pair<const Key , T> 是一个内部类函数也是一个类模板

 和搜索二叉树的KV模型对比:

就是把搜索二叉树的K和V存入了一个类模板结构中 ,而pair这个类模板的内部中的 first表示键 Key,second表示值 Value

插入操作 

对于map的inser操作t在有了pair后,实际上就是插入一个pair 

dict.insert({"String","字符串"})是一种隐式类型转化,但是需要注意这种隐式类型转化要和构造函数中的initializer_list<value_type>进行区分:

如上图代码所示,上图代码是一个构造函数。

遍历操作 

可以看到图上代码中的<<出现了问题,这其实和pair有关,因为pair内部其实是两个数值,所以迭代器并不知道应该返回谁,且pair并不支持流插入操作,所以需要进行深入的操

前文说过,pair内部的Key 和 Value数值是使用first和second来替代的。

 简化写法1:

简化写法2:可以省略箭头,和list的operator->的箭头省略操作一样

 可以看出如果我们要实现map底层代码中的的迭代器,那么将会较为的困难。

注意事项:

在遍历map的时候,pair的first是不允许进行修改的,而second却可以进行修改:

firs是key相对于树的节点和各类节点之间具有关系,所以是不能进行修改的,因为map是靠key进行排序的!

使用范围for进行遍历:
 写法1:

写法2:

写法2是建立在当前编译器的C++版本处在C++17,而在此之前的写法是C++11版本的

构造操作: 

operator[] 

map的operator[]和之前的operator[]不同,以前[]内部是一个下标,就例如vector的operator[] []内部的参数是下标,而map的operator[]的[]内部是一个key,内部是一个key然后返回一个key对应的value

如下图所示, operator[]的内部和insert有关,主要是利用了map的insert的性质:

  • 如果插入的元素在map中已经存在了,那么就返回一个pair<存在的key所在的节点的迭代器,false>
  • 如果插入的元素在map不存在,则返回一个pair<新插入的key所在的迭代器,true>

所以插入是否成功关键在于返回的pair内部的second,且无论插入是否成功key所在节点的迭代器都会被返回,而如果插入的是同一个key但是value不一样,那么就算插入了也是无效,因为编译器不会更改value的数据。

operator[]的使用 

  • 从这里看出insert是一个查找的功能
  • 所以为什么[]内部是放置key的就是为了传递key让后让insert去查找这个key是否在map中是否存在,如果存在则返回false,而后通过pair获取key所在的节点的迭代器(ret.frist)然后再通过这个迭代器来获取这个迭代器所对应的second也就是value
  • 图中的it->second是一个简写
 operator[]的多种写法

注意插入+修改 和 修改,如果有[]内部的key数值,那么就变成修改,没有就变成插入功能 

查找操作
使用find进行查找

这个函数表达的是 水果的名字表示为frist 也就是 Key ,而水果出现的次数则是second 也就是Value。

使用find查找string arr[]内部的所有数据是否又在map中出现过,如果有,find会返回一个该数据在map中的节点位置,以迭代器的形式进行返回,如果没有会返回一个end, 那么当返回值不等于end时则会让map中的这个数据的value次数加1。

而代码会在,没有出现这个数据是,进行插入操作,同时插入这个数据也要把这个数据出现的次数1也需要进行插入。

使用operator[]进行查找

  • 在这里的countMap[e]++内部的e是一个key表示arr[]内部的数据,如果arr内部的数据没有在countMap中出现,那么则会进行插入+修改操作
  • 例如苹果没有出现则会插入苹果,而苹果出现的次数在插入的过程中会被初始化成0,而在++后变成了1
  • 而·如果苹果存在与countMap中后[]会进行查找并且返回,而又因为countMap的scond内部存储的是次数,而[]无论查找成功还是失败都会返回,因为这里查找成功后返回了second然后因为++scond则开始+1
  • 所以苹果次数会变成2
count 

给一个key然后返回这个key在map内部的个数,可以进行判断key是否存在:

如上代码所示,输入一个str字符串,看是否在map中是否存在,如果存在则输出在,不存在则输出不在。

使用second排序操作 和 multimap

 使用另一个map,将次数和字符串进行颠倒,使用遍历赋值的方法,如上图所示,原先的string变成了second的位置,而原先的int变成了frist的位置

  • 进行对比发现,少了一个草莓,原因是草莓和香蕉的frist重复了,且香蕉是后面进行遍历赋值的,而且使用了[]导致了后面变成了key=2的value=草莓被修改成了key=2 value=香蕉
  • 因为使用了[]然后查找到了之后被修改了,这是因为[]具有修改的操作
  • 而如果使用了insert则会导致香蕉插入失败,因为insert是不具有修改功能的,所以因为key都等于2,所以当轮到香蕉时,算是找到了所以无法进行修改

 所以想要进行second排序则需要使用 multimap,这是因为multimap允许冗余,也就是允许map的key重复,而map不允许key重复

 这个是查找多个重复的key的 ,最后返回的是第一个重复的key的迭代器,和最后一个重复key的迭代器的前一个位置  的函数


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言——指针的奥秘(1.0)

指针 一.内存和地址1.内存2.编址 二.指针变量和指针1.取地址操作符&#xff08;&&#xff09;2.指针变量和解引用操作符&#xff08;*&#xff09;1.指针变量2.拆解指针类型3.解引用操作符4.指针变量的大小 三.指针变量的类型和意义1.指针的解引用2.指针 - 整数3.void* 指针…

JVM笔记1--Java内存区域

1、运行时数据区域 从上图可以看出来&#xff0c;Java虚拟机运行时数据区域整体上可以分成5大块&#xff1a; 1.1、程序计数器 程序计数器是一块较小的内存空间。它可以看做当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里&#xff0c;字节码解释器工作时就是…

OpenAI下周将发布ChatGPT搜索引擎,挑战谷歌搜索!

目前&#xff0c;多方位消息证实&#xff0c;OpenAI将会在5月9日上午10点公布该消息&#xff0c;大约是北京时间周五的凌晨2点。 5月3日&#xff0c;前Mila研究员、麻省理工讲师Lior S爆料&#xff0c;根据OpenAI最新的SSL证书日志显示&#xff0c;已经创建了search.chatgpt.c…

Java集合排序

1. 集合排序API 1.1 集合排序概述 集合排序是指对一个集合中的元素按照特定规则进行重新排列&#xff0c;以使得集合中的元素按照预定义的顺序呈现。 在集合排序中&#xff0c;通常需要定义一个比较规则&#xff0c;这个比较规则用于决定集合中的元素在排序后的顺序。元素之间…

KIE基于图模型的关键信息抽取源码详解

1.数据集准备 下载数据集 https://download.openmmlab.com/mmocr/data/wildreceipt.tar WildReceiptOpenset 准备好 WildReceipt。 转换 WildReceipt 成 OpenSet 格式: # 你可以运行以下命令以获取更多可用参数: # python tools/dataset_converters/kie/closeset_to_opens…

程序的机器级表示——Intel x86 汇编讲解

往期地址&#xff1a; 操作系统系列一 —— 操作系统概述操作系统系列二 —— 进程操作系统系列三 —— 编译与链接关系操作系统系列四 —— 栈与函数调用关系操作系统系列五 —— 目标文件详解操作系统系列六 —— 详细解释【静态链接】操作系统系列七 —— 装载操作系统系列…

java下乡扶贫志愿者招募管理系统springboot-vue

计算机技术在现代管理中的应用&#xff0c;使计算机成为人们应用现代技术的重要工具。能够有效的解决获取信息便捷化、全面化的问题&#xff0c;提高效率。 技术栈 前端&#xff1a;vue.jsElementUI 开发工具&#xff1a;IDEA 或者eclipse都支持 编程语言: java 框架&#xff1…

c++ 红黑树学习及简单实现

1. 了解红黑树 1.1. 概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个节点增加一个存储位表示节点的颜色&#xff0c;可以是红色&#xff0c;或是黑色&#xff0c;通过对任何一条从根到叶子的路径上各个节点的着色方式进行限制&#xff0c;红黑树确保没有一条路…

Dockerfile镜像实例

目录 一、构建SSH镜像 1. 建立工作目录 2. 生成镜像 3. 启动容器并修改root密码 二、systemctl镜像 1. 建立工作目录 2. 生成镜像 3. 运行镜像容器 ​编辑 4. 测试容器systemct 三、Nginx镜像 1. 建立工作目录 2. 编写Dockerfile脚本 3. 编写run.sh启动脚本 4. …

IDEA启动Tomcat启动失败:jar包未部署【部署jar包】

IDEA启动Tomcat报错java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener&#xff1a;jar包未部署【部署jar包】 学习java&#xff0c;开始跟着教程的步伐学习maven下载jar包&#xff0c;tomcat启动项目&#xff0c;发现项目未启动成功也…

虾皮(Shopee)商品详情API接口:轻松获取商品深度信息

API接口概述 虾皮的商品详情API接口是专为商家和开发者提供的服务接口&#xff0c;通过该接口&#xff0c;您可以快速、准确地获取指定商品的详细信息。这些信息包括但不限于商品标题、价格、库存、描述、图片、规格参数等&#xff0c;为您的商品展示、比价、推荐等场景提供有…

C++设计模式-结构型设计模式

写少量的代码来应对未来需求的变化。 单例模式 定义 保证一个类仅有一个实例&#xff0c;并提供一个该实例的全局访问点。——《设计模式》GoF 解决问题 稳定点&#xff1a; 类只有一个实例&#xff0c;提供全局的访问点&#xff08;抽象&#xff09; 变化点&#xff1a…

SpringCloud微服务:Eureka 和 Nacos 注册中心

共同点 都支持服务注册和服务拉取都支持服务提供者心跳方式做健康检测 不同点 Nacos 支持服务端主动检测提供者状态&#xff1a;临时实例采用心跳模式&#xff0c;非临时&#xff08;永久&#xff09;实例采用主动检测模式Nacos 临时实例心跳不正常会被剔除&#xff0c;非临时实…

【uniapp】H5+、APP模拟浏览器环境内部打开网页

前言 今天将智能体嵌入到我的项目中&#xff0c;当作app应用时&#xff0c;发现我使用的webview组件&#xff0c;无论H5怎么登录都是未登录&#xff0c;而APP却可以&#xff0c;于是进行了测试&#xff0c;发现以下几种情况&#xff1a; 方法<a>标签webviewAPP✅✅网页…

YOLOv5改进之bifpn

目录 一、原理 二、代码 三、在YOLOv5中的应用 一、原理 论文链接:

课题学习(二十三)---三轴MEMS加速度计芯片ADXL372

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。 一、基础配置 测量范围-200g-200g&#xff0c;分辨率为12位&#xff0c; V s 、 V D D I / O V_s、V_{DDI/O} Vs​、VDDI/O​范围为1.6V-3.5V 1.1 引脚配…

【银角大王——Django课程——用户表的基本操作2】

用户表的基本操作2 编辑用户按钮删除按钮入职日期——不显示时分&#xff0c;只显示年月日——使用DataField函数不使用DateTimeField修改models记得重新执行命令&#xff0c;更新数据库结构修改前修改后 编辑用户按钮 点击编辑&#xff0c;跳转到编辑页面&#xff08;将编辑的…

CrossOver支持的软件多吗 CrossOver支持软件列表 crossover兼容性查询

如果你是一个喜欢在Mac上工作的用户&#xff0c;但又不想放弃一些Windows上的优秀软件&#xff0c;那么可以考虑使用一些兼容工具来运行Windows程序。其中&#xff0c;CrossOver就是一款功能强大且受欢迎的兼容工具。那么&#xff0c;CrossOver到底能支持哪些Windows软件呢&…

JVM笔记2--垃圾收集算法

1、如何确认哪些对象“已死” 在上一篇文章中介绍到Java内存运行时的各个区域。其中程序计数器、虚拟机栈、本地方法栈3个区域随着线程而生&#xff0c;随线程而灭&#xff0c;栈中的栈帧随着方法的进入和退出而有条不紊的执行着入栈和出栈操作。每个栈帧中分配多少内存基本上…

VMvare如何更改虚拟机内共享文件夹的挂载点

更改虚拟机内共享文件夹的路径 进入目录 /etc/init.d ,并找到vmware-tools文件 里面有配置项 vmhgfs_mnt"/mnt/hgfs" 将引号内的内容更改为你需要挂载的路径,重启即可 注意挂载的路径不能是 “/”&#xff0c;必须根目录下的某个文件夹&#xff0c;或者其子文件夹 …
最新文章