C++笔记---set和map
1. 序列式容器与关联式容器
前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联关系,比如交换⼀下,他依旧是序列式容器。
顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。
关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联关系,交换一下,他的存储结构就被破坏了。
顺序容器中的元素是按关键字来保存和访问的。
关联式容器有map/set系列和unordered_map/unordered_set系列。
本章节讲解的map和set底层是红黑树,红黑树是一颗平衡二叉搜索树。
set/multiset是key搜索场景的结构, map/multimap是key/value搜索场景的结构。
set/map不支持相同的值插入,multiset/multimap支持相同的值插入。
2. pair类
在正式介绍set和map之前,我们需要先了解一下pair类。
这个类也是一个类模板,顾名思义,它的作用就是存储两个数据,也即将两个数据绑定到一起。
在需要返回两个数据的场景下,我们就可以将两个数据存到pair中进行返回。
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){}// 支持隐式类型转换template<class U, class V>pair(const pair<U, V>& pr) : first(pr.first), second(pr.second){}
};// C++11之间常用的构造pair的函数
template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{return (pair<T1, T2>(x, y));
}
3. set的介绍
参考文档:set - C++ Reference,关于set的使用,将其当作key搜索场景的红黑树来使用即可。
set的原型:
template < class T, // set::key_type/value_typeclass Compare = less<T>, // set::key_compare/value_compareclass Alloc = allocator<T> // set::allocator_type> class set;
类型参数分别为:key的类型,比较器(通过仿函数实现,默认为小于比较,中序遍历得到升序序列),内存池。
一般来说,后两个参数有缺省值,的使用频率较低,我们在日常使用的过程中只需要传入第一个参数即可。
3.1 常用接口
STL的容器都是大同小异,这里只列出需要注意的。
3.1.1 构造函数
set(); | 默认构造 |
template <class InputIterator> set(InputIterator first, InputIterator last); | 迭代器区间构造 |
set(const set& x); | 拷贝构造 |
在C++11之后还支持用列表构造:
// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());eg:
set<int> mySet1({1, 2, 3, 4});
set<int> mySet2 = {1, 2, 3, 4};
在原文档中,前两个构造函数的参数列表还包括比较器和内存池:
但是经过我自己的测试发现,如果在定义set的时候传入比较器或内存池,这个定义语句会被编译器识别成函数的声明:
也就是说,比较器和内存池依然只能在类型参数列表中传入。
3.1.2 迭代器
这里就不列表了,set的迭代器是双向迭代器,函数还是那几个函数。
正向迭代器的是按照key值从小到大进行遍历。
除此之外,在set中无论是iterator还是const_iterator都不支持通过解引用修改set中的数据,因为这样会破坏红黑树的底层结构。
3.1.3 增删
(1)pair<iterator, bool> insert(const value_type& val); (2)iterator insert(iterator position, const value_type& val); (3)template <class InputIterator> void insert(InputIterator first, InputIterator last); | (1)按值插入 (2)指定位置插入 (3)将容器的迭代器区间内的值插入 |
(1)void erase(iterator position); (2)size_type erase(const value_type& val); (3)void erase(iterator first, iterator last); | (1)删除指定位置的值 (2)删除指定的值 (3)删除一个迭代器区间 |
insert函数(1)的返回值是一个pair:
插入成功时:iterator为新插入数据的迭代器,bool为true
插入失败时:iterator为已有的相同值的迭代器,bool为false
insert函数(2)的第一个参数实质上只是一个插入建议,由于set的特殊的红黑树的底层结构,该插入建议可能不会被采纳。
3.1.4 查找
iterator find (const value_type& val) const; | 查找某个值 |
size_type count (const value_type& val) const; | 查找某个值在set中有几个 |
set不支持相同的值进行插入,所以count的结果不是1就是0。
这样看来count似乎有点鸡肋,或者说与名称不符,但set中的count实际上是为了与multiset统一而存在的。
但count也并非一无是处,如果只想确定某个值存不存在的话,count就稍微比find方便一点:
if(mySet.find(24) != mySet.end())
{// ......
}if(mySet.count(24))
{// ......
}
3.2 multiset
基本与set相同,但是支持插入相同的数据,由此而引发的变化还有:
1. insert一定成功,插入函数(1)的返回值不再是pair而只有iterator。
2. count返回数据在set中的个数。
3. 如果有多个相同的值,无论是删除还是查找,都是对中序遍历的第一个进行操作。
4. map的介绍
参考文档:map - C++ Reference,关于map的使用,将其当作key/value搜索场景的红黑树来使用即可。
map的原型:
template < class Key, // map::key_typeclass T, // map::mapped_typeclass Compare = less<Key>, // map::key_compareclass Alloc = allocator<pair<const Key,T> > // map::allocator_type> class map;
类型参数分别为:key的类型,value的类型,比较器(通过仿函数实现,默认为小于比较,中序遍历得到升序序列),内存池。
除此之外,pair在map中起到了将key和value绑定到一起的作用,所以在map的结点中存的数据实际上是pair,而没有单独存储key和value。
typedef pair<const Key, T> value_type;
同样,大多数情况下只需要传入前两个参数即可。
4.1 常用接口
同样,此处只列出较为重要或与其他容器有所不同的。
4.1.1 构造函数
map(); | 默认构造 |
template <class InputIterator> map (InputIterator first, InputIterator last); | 迭代器区间构造 |
map (const map& x); | 拷贝构造 |
在C++11之后支持列表构造:
// initializer list (5) initializer 列表构造
map (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());eg:
map<string, int> myMap1({{"张三", 18}, {"李四", 21}, {"王五", 35}});
map<string, int> myMap2 = {{"张三", 18}, {"李四", 21}, {"王五", 35}};
内层大括号会通过pair的列表构造隐式类型转换为pair<string, int>类型。
关于参考文档中给出的函数原型,依然存在着和set相同的问题。
4.1.2 迭代器
函数还是那些函数,迭代器还是双向迭代器。
但与set不同的是,map的迭代器支持对value进行修改,而依然不支持对key进行修改。
由于map结点中存的是pair<key, value>,所以按照逻辑来说,map的迭代器解引用得到的就是pair<key, value>。
在pair中,key对应的是first,value对应的是second:
map<string, int> myMap(...);
map<string, int>::iterator it = myMap.begin();
while(it != myMap.end())
{cout << "key:" << (*it).first << " value:" << *(it).second << endl;cout << "key:" << it->first << " value:" << it->second << endl;
}
4.1.3 增删
(1)pair<iterator, bool> insert(const value_type& val); (2)iterator insert(iterator position, const value_type& val); (3)template <class InputIterator> void insert(InputIterator first, InputIterator last); | (1)按值插入 (2)指定位置插入 (3)将容器的迭代器区间内的值插入 |
(1)void erase(iterator position); (2)size_type erase(const key_type& k); (3)void erase(iterator first, iterator last); | (1)删除指定位置的值 (2)删除指定的值 (3)删除一个迭代器区间 |
函数原型与set完全一样,除了erase函数(2),只需要key即可找到对应的数据进行删除。
但是要切记,这里的value_type是pair。
insert函数(1)的返回值逻辑也与set相同,但是只要key相同就不支持继续插入了。
4.1.4 查找
iterator find (const key_type& k); const_iterator find (const key_type& k) const; | 按键值key查找 |
size_type count (const key_type& k) const; | 查找某个键值key在set中有几个 |
同样这里的count函数的返回值也只能是1或0。
4.1.5 operator[]
没错,map重载了"[]"。
但是,按理来说,只有支持随机迭代器的容器才可以重载"[]",而map不是双向迭代器吗?
看了函数原型你就明白了:
mapped_type& operator[] (const key_type& k);
所以,这个"[]"的功能是根据key来返回value的引用,而与迭代器没有关系。
但这个函数并不简单:
当key存在时,返回其对应的value的引用。
当key不存在时,在map中插入key,并给value默认值,然后返回value的引用。
所以map中的"[]"可以说是"查找,修改,插入"三位一体。
这是由于operator[]的内部实现是基于insert函数完成的:
// operator[]的内部实现
mapped_type& operator[] (const key_type& k)
{// 1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储//mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能// 2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的//迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能pair<iterator, bool> ret = insert({ k, mapped_type() });iterator it = ret.first;return it->second;
}
4.2 multimap
基本与map相同,但是支持插入相同的数据,由此而引发的变化还有:
1. insert一定成功,插入函数(1)的返回值不再是pair而只有iterator。
2. count返回数据在map中的个数。
3. 如果有多个相同的值,无论是删除还是查找,都是对中序遍历的第一个进行操作。
4. 不再支持operator[],因为同一个key存在多组值。
相关文章:

C++笔记---set和map
1. 序列式容器与关联式容器 前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联关…...

HTTP 教程
HTTP/HTTPS 简介 HTTP(Hypertext Transfer Protocol,超文本传输协议)和 HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议)是用于在网络中传输信息的两种主要协议。它们定义了客户端和服务器…...

低代码革命:加速云原生时代的端到端产品创新
随着云计算技术的飞速发展,云原生成为了企业数字化转型的重要方向。云原生技术通过容器化、微服务、持续集成/持续部署(CI/CD)等实践,帮助企业构建和运行可扩展的应用程序。然而,云原生技术的复杂性也给开发团队带来了…...

力扣 92.反转链表Ⅱ
力扣《反转链表》系列文章目录 刷题次序,由易到难,一次刷通!!! 题目题解206. 反转链表反转链表的全部 题解192. 反转链表 II反转链表的指定段24. 两两交换链表中的节点两个一组反转链表 题解225. K 个一组翻转链表K …...

2024年最新版TypeScript学习笔记——泛型、接口、枚举、自定义类型等知识点
今天带来的是来自尚硅谷禹神2024年8月最新的TS课程的学习笔记,不得不说禹神讲的是真的超级棒! 文章目录 TS入门JS中的困扰静态类型检查编译TS命令行编译自动化编译 类型检查变量和函数类型检查字面量类型检查 类型推断类型声明声明对象类型声明函数类型…...

java项目之城镇保障性住房管理系统(源码+文档)
风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的城镇保障性住房管理系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 城镇保障性住房管…...

无人机之航线规划篇
无人机的航线规划是一个复杂但至关重要的过程,它确保了无人机在飞行过程中的安全、高效以及任务的顺利完成。以下是对无人机航线规划的详细解析: 一、定义与目的 无人机航线规划是指依据无人机任务分配,规划出符合安全条件的飞行航线。这一过…...

828 华为云征文|华为 Flexus 云服务器搭建 PicGo 图床
在这个充满非凡意义的日子里,我怀揣着满心的热忱与憧憬,毅然决然地踏上了借助华为 Flexus 云服务器搭建 PicGo 图床的精彩征程。这段旅程,注定充满了无数的挑战与意外之喜,宛如在广袤无垠的数字海洋中勇敢地探寻那神秘而珍贵的宝藏…...

Zabbix 6.4添加中文语言
/usr/share/zabbix/include/locales .inc .phplocale -agrep “zh_CN" yum install langpacks-zh_CN.noarch y y y...

【退役之再次线上部署】Spring Boot + VUE + Nginx + MySQL
这篇博客写在凌晨 4 点 20 分,这个时候我刚线上部署完成 web 项目,自己写的全栈项目 这个点儿,也睡不着了,索性就写篇博客记录一下 一、踩坑实录 这个是 最重要的,所以写在前面 Nginx 配置文件 location location /a…...

Qanything 2 0源码解析系列1:新建知识库
Qanything 2.0源码解析系列1:新建知识库 文章转载自:https://www.feifeixu.top/article/19c76951-5881-4181-bb63-4188b28d3917 😀 前言: qanything所有接口都定义在sanic_api.py中 接口函数定义在同级目录下的handler.py中 新建…...

Redis-01 入门和十大数据类型
Redis支持两种持久化方式:RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上,可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照,可以通过恢复RDB文件来恢复数据。 2.AOF持久化…...

IT行业的现状与未来发展趋势
IT行业的现状与未来发展趋势 近年来,随着科技的迅猛发展,IT行业无疑已经成为全球经济增长的重要驱动力之一。无论是人工智能、大数据,还是云计算和区块链技术,IT行业的创新始终在不断推动着各个领域的变革。 人工智能的广泛应用…...

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建Jenkins CI/CD平台
828华为云征文 | 云服务器Flexus X实例,Docker集成搭建Jenkins CI/CD平台 Jenkins 是一个开源的自动化服务器,用于持续集成(CI)和持续交付(CD)软件项目。它允许开发人员在软件开发过程中自动化各种任务&…...

今日 leetCode 15.三数之和
15. 三数之和 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元…...

Games101笔记-二维Transform变换(二)
1、什么是Transform Transform就是通过一个矩阵,进行缩放、旋转、平移等变换 2、缩放、旋转、切变、平移等基础变换 缩放变换: 反射变换: 切变: 绕原点旋转: 以上都是线性变换: 平移变换…...

【洛谷】AT_abc371_c [ABC371C] Make Isomorphic 的题解
【洛谷】AT_abc371_c [ABC371C] Make Isomorphic 的题解 洛谷传送门 AT传送门 题解 抽象题目,抽象翻译,可能是我太菜了,根本没看懂题目,后面是听大佬讲题才发现,这不就是一题全排列暴力题吗。谔谔,真的…...

全国职业院校技能大赛(大数据赛项)-平台搭建Spark、Scala笔记
Spark作为一个开源的分布式计算框架拥有高效的数据处理能力、丰富的生态系统、多语言支持以及广泛的行业应用。Scala是一种静态类型的编程语言,它结合了面向对象编程和函数式编程的特性,被誉为通用的“大数据语言”。而二者的结合更能迸发出新奇的化学反…...

【Java】JVM基本组成
一、JDK、JRE、JVM JDK:全称 “Java Development Kit” Java 开发工具包,提供 javac编译器、jheap、jconsole 等监控工具; JRE:全称 “Java Runtime Environment” Java 运行环境,提供 class Library 核心类库JVM; …...

解决【WVP服务+ZLMediaKit媒体服务】加入海康摄像头后,能发现设备,播放/点播失败,提示推流超时!
环境介绍 每人搭建的环境不一样,情况不一样,但是原因都是下面几种: wvp配置不当网络端口未放开网络不通 我搭建的环境: WVP服务:windows下,用idea运行的源码 ZLM服务:虚拟机里 问题描述 1.…...

淘宝商品详情接口item_get响应参数解析:props、props_list、prop_img
在电商数据分析和应用开发中,淘宝商品详情接口item_get是一个至关重要的工具。通过该接口,开发者可以高效地获取淘宝平台商品的详细信息,从而优化商品展示、搜索、推荐等功能,提升用户体验和转化率。本文将详细解析item_get接口的…...

Android使用OpenCV 4.5.0实现扑克牌识别(源码分享)
一、显示效果展示 二、OpenCV 4.5.0 OpenCV 4.5.0是OpenCV(Open Source Computer Vision Library,开源计算机视觉库)的一个重要更新版本,该版本在多个方面进行了优化和新增了多项功能。 三、ONNX模型 ONNX(Open Neu…...

Pandas_iloc_loc_哪个是inclusive哪个是exclusive
iloc 和 loc 包括不包括结尾写的那个行(列)? 不一样! iloc[istart:iend] exclusive on iend 不包括结尾那行(列)! loc[start:end] inclusive on end 包括结尾那行(列)&am…...

python是什么语言写的
Python是一种计算机程序设计语言。是一种面向对象的动态类型语言。现今Python语言很火,可有人提问,这么火的语言它的底层又是什么语言编写的呢? python是C语言编写的,它有很多包也是用C语言写的。 所以说,C语言还是很…...

python编程,把所有子目录和文件输出到文本文件
要将所有子目录和文件输出到文本文件,你可以使用Python的os模块来遍历目录结构,并将结果写入文件。以下是一个简单的Python脚本示例,它会递归地遍历指定目录,并将每个子目录和文件的相对路径写入到一个文本文件中: im…...

使用 IntelliJ IDEA 连接到达梦数据库(DM)
前言 达梦数据库是一款国产的关系型数据库管理系统,因其高性能和稳定性而被广泛应用于政府、金融等多个领域。本文将详细介绍如何在 IntelliJ IDEA 中配置并连接到达梦数据库。 准备工作 获取达梦JDBC驱动: 访问达梦在线服务平台网站或通过其他官方渠道…...

【Python报错已解决】AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…...

Java中的事件(动作监听-ActionListener)
(一)、ActionListener接口 ActionListener接口用于处理用户界面上的动作事件,例如:按钮点击、菜单选择等。实现ActionListener接口需要重写actionPerformed(ActionEvent e)方法,该方法会在动作发生时被调用。 &#…...

STM32篇:开发环境安装
编程语言:C语言 需要安装的软件有两个:Keil5 和 STM32CubeMX 一.Keil5 的安装 使用 Keil4 写 STM32 代码其实也是可以,但需要很复杂的配置,不建议新手操作。 比较推荐 Keil5 编写 STM32 ,只需要一些简单的设置就可…...

AIGC实战——多模态模型Flamingo
AIGC实战——多模态模型Flamingo 0. 前言1. Flamingo 架构2. 视觉编码器3. Perceiver 重采样器4. 语言模型5. FIamingo 应用小结系列链接0. 前言 我们已经学习了文本生成图像模型 DALL.E 2,在本节中,我们将探索另一种多模态模型 Flamingo,它可以根据给定文本和视觉数据流生…...