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.mzph.cn/news/75509.shtml

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

相关文章

关于软件的功能复用

有一些人总在说软件要复用&#xff0c;开发一个项目时要想想怎么在另一个项目中能重用。你问他怎么做到复用&#xff0c;就会听到微服务、中台一些名词 复用的层次 说到复用&#xff0c;首先要想明白复用的是啥 级别越低&#xff0c;粒度越小&#xff0c;复用的范围越广&#…

Yolov5改进算法之添加Res2Net模块

目录 1. Res2Net介绍 1.1 Res2Net的背景和动机 1.2 Res2Net的基本概念 2. YOLOV5添加Res2Net模块 Res2Net&#xff08;Residual Resolution Network&#xff09;是一种用于图像处理和计算机视觉任务的深度卷积神经网络架构。它旨在解决传统的ResNet&#xff08;Residual Ne…

【java】【SSM框架系列】【三】Maven进阶

目录 一、分模块开发与设计 1.1 分模块开发的意义 1.2 分模块开发&#xff08;模块拆分&#xff09; 二、依赖管理 2.1 依赖传递 2.2 可选依赖 2.3 排除依赖 三、聚合与继承 3.1 聚合 3.2 继承 3.3 聚合与继承的区别 四、属性管理 4.1 属性 4.1.1 属性配置与使用 …

2023 年高教社杯全国大学生数学建模竞赛题目 B 题 多波束测线问题

B 题 多波束测线问题 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀速直线传播&#xff0c;在不同界面上产生反射&#xff0c;利用这一原理&#xff0c;从测量船换能器垂直向海底发射声波信号&#xff0c;并记录从声波发射到信号接收的传播…

智慧工地:让工地可视化、数字化、智能化

智慧工地平台功能包括&#xff1a;劳务管理、施工安全管理、视频监控管理、机械安全管理、危大工程监管、现场物料监管、绿色文明施工、安全隐患排查、施工综合管理、施工质量管理、设备管理、系统管理等模块。 一、项目开发环境 技术架构&#xff1a;微服务 开发语言&#…

数据结构--- 树

(一)知识补充 定义 树是一种数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。​ 它具有以下的特点: 每个节点有零个或多个子节点; 没有父节点的节点称为根节点;每一个非根…

算法训练营day44|动态规划 part06:完全背包 (完全背包、 LeetCode518. 零钱兑换 II、377. 组合总和 Ⅳ )

文章目录 完全背包518. 零钱兑换 II (求组合方法数)思路分析代码实现思考总结 377. 组合总和 Ⅳ (求排列方法数)思路分析代码实现思考总结 完全背包 完全背包和01背包问题唯一不同的地方就是&#xff0c;每种物品有无限件。 依然举这个例子&#xff1a; 背包最大重量为4。 物…

【LInux编译器gcc/g++】gcc使用方法和动静态库相关概念

目录 一.前言 二.源代码的翻译环境 三.gcc相关指令 四.动静态库 1.什么是库&#xff1f; 2.库的命名 3.库的链接方式 4.动静态链接的优缺点 5.小结 一.前言 在Windows系统上我们常用VisualStudio来进行C/C开发&#xff0c;VS并不是一款单一的软件&#xff0c;而是集成…

【刷题篇】贪心算法(一)

文章目录 分割平衡字符串买卖股票的最佳时机Ⅱ跳跃游戏钱币找零 分割平衡字符串 class Solution { public:int balancedStringSplit(string s) {int lens.size();int cnt0;int balance0;for(int i0;i<len;i){if(s[i]R){balance--;}else{balance;}if(balance0){cnt;}}return …

WPF CommunityToolkit.Mvvm Messenger通讯

文章目录 环境WeakReferenceMessenger方法介绍无回调订阅发送Token区分有回调订阅发送 环境 CommunityToolkit.Mvvm Messenger 十月的寒流: 如何使用 CommunityToolkit.Mvvm 中的 Messenger 来进行 ViewModel 之间的通信 WeakReferenceMessenger 我这里只讲简单的弱Messenger…

Spring云服务:如何将应用程序轻松迁移到云端

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Android图形-Hardware Composer HAL

目录 一、引言 二、概览 三、实现HWC 3.1 为什么是HWC&#xff1f; 3.2 HWC的支持需求 3.3 HWC的实现思路 3.4 HWC的基元 3.5 HIDL接口 3.6 函数指针 3.7 图层和屏幕句柄 3.8 屏幕合成操作 3.9 多个屏幕 3.10 虚拟屏幕合成 3.10.1 模式 3.10.2 输出格式 3.11 同…

Qt 5.15编译(MinGW)及集成Crypto++ 8.8.0笔记

一、背景 为使用AES加密库&#xff08;AES/CBC加解密&#xff09;&#xff0c;选用Crypto 库&#xff08;官网&#xff09;。   最新Crypto C库依次为&#xff1a;8.8.0版本&#xff08;2023-6-25&#xff09;、8.7.0&#xff08;2022-8-7&#xff09;和8.6.0&#xff08;202…

如何利用 Selenium 对已打开的浏览器进行爬虫

大家好&#xff01; 在对某些网站进行爬虫时&#xff0c;如果该网站做了限制&#xff0c;必须完成登录才能展示数据&#xff0c;而且只能通过短信验证码才能登录 这时候&#xff0c;我们可以通过一个已经开启的浏览器完成登录&#xff0c;然后利用程序继续操作这个浏览器&…

【LeetCode-中等题】39. 组合总和

文章目录 题目方法一&#xff1a;递归回溯 题目 这题的nums数组里面不存在重复元素&#xff0c;所以也就无需做去重操作 但同一个元素可以被无限次取&#xff0c;说明每次递归中的for循环的开始位置就是自己 nums数组里面存在重复元素&#xff0c;去重版本&#xff1a; 方法一…

Git学习记录

Contest 一、工作区域二、操作命令2.1 创建仓库2.2 查看仓库状态2.3 从工作区向暂存区添加文件2.3.1 只添加一个文件2.3.2 添加全部文件 2.4 从暂存区向仓库区添加文件2.5 查询日志2.5.1 从当前版本开始查询2.5.2 查看所有日志 2.6 回滚2.6.1 从仓库回滚到工作区2.6.2 取消工作…

剑指 Offer 04. 二维数组中的查找

题目描述 在一个 n * m 的二维数组中&#xff0c;每一行都按照从左到右 非递减 的顺序排序&#xff0c;每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含有该整数。 解题思路 注意每…

c++中的list容器讲解

文章目录 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.6 list的迭代器失效 2. list的模拟实现2.1 模拟实现list 3. list与vector的对比 1. list的介绍及使用 1.1 list的介绍 …

医疗知识图谱 neo4j

开源项目&#xff1a; https://github.com/liuhuanyong/QASystemOnMedicalKG 一.效果 二.需要安装&#xff1a; pip install pyahocorasick pip install py2neo 三.需要修改&#xff1a; 需要改的点&#xff1a; 1.改连接的方式 2.改读文件的方式 MedicalGraph 运行&am…

docker-compose安装Nacos2

文章目录 一. Mac1.1 数据库nacos_dev1.2 docker-compose.yaml1.3 部署1.4 卸载1.5 查看 二. Win102.1 docker-compose.yaml2.2 部署2.3 卸载 一. Mac 1.1 数据库nacos_dev sql文件地址 /** Copyright 1999-2018 Alibaba Group Holding Ltd.** Licensed under the Apache Li…