【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:初步了解 二叉搜索树
🌹🌹期待您的关注 🌹🌹



❀map与set
- 📒1. 关联式容器
- 📙2. 键值对
- 📕3. 树形结构的关联式容器
- 📜4. set 与 multiset
- 🎩set的概念
- 🎈multiset的概念
- 🧩set的使用
- 🌈set的模板参数列表
- 🌞set的构造
- 🌙set的迭代器
- ⭐set的其他函数操作
- 📚5. map 与 multimap
- 🎩map的概念
- 🎈multimap的概念
- 🧩map的使用
- 🌈map的模板参数说明
- 🌞map的构造
- 🌙map的迭代器
- ⭐map的其他函数操作
- 📖6. 总结拓展
- 💧在实际中的应用
- 🔥总结
前言: 在编程的世界里,数据结构的选择往往决定了程序的效率和稳定性。而在C++的STL(Standard Template Library)库中,map和set无疑是两颗璀璨的瑰宝。它们以其独特的数据存储和检索方式,为我们提供了高效且有序的键值对存储和集合管理方案
map和set不仅拥有自动排序的特性,还提供了丰富的成员函数和迭代器接口,使得我们可以轻松地对其进行操作和管理。无论是在算法竞赛中,还是在日常编程中,它们都是不可或缺的工具
我们将从map和set的定义和特性开始,介绍它们的基本用法和常用成员函数。接着,我们将通过示例代码,展示如何在实际编程中使用它们。同时,我们还将探讨一些常见的错误用法和注意事项,帮助你避免在使用map和set时遇到坑
让我们一起踏上学习 map与set 的旅程,探索它带来的无尽可能!
📒1. 关联式容器
在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、
forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身
关联式容器(Associative Containers) 是C++标准模板库(STL)中的一类重要容器,主要用于存储和快速检索键值对(key-value pairs)形式的数据。这类容器与序列式容器(如vector、deque、list)的主要区别在于,关联式容器中的元素是按照特定的排序准则(通常是键的大小)进行排序的,从而允许通过键来快速查找、插入和删除元素
关联式容器: 也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高
📙2. 键值对
概念: 用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息,比如我们上一篇所提到的kv模型结构 存在对应关系


SGI-STL中关于键值对的定义:(示例)
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){}
};
📕3. 树形结构的关联式容器
根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。
- 树型结构的关联式容器主要有四种:map、set、multimap、multiset
- 共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列
关联式容器是C++ STL中一类重要的容器,它们通过键值对的形式存储数据,并支持快速的查找、插入和删除操作。常见的关联式容器包括set、multiset、map和multimap等,它们在不同的应用场景下提供了高效的解决方案
📜4. set 与 multiset
🎩set的概念
概念: set 是 C++ 标准模板库 (STL) 中的一个关联式容器,它包含的元素是唯一的,且默认情况下元素会按照升序排序。set 的内部实现通常使用红黑树来保持其有序性和唯一性
- set是按照一定次序存储元素的容器
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的
- set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代
- set在底层是用二叉搜索树(红黑树)实现的
特征:
- 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对
- set中插入元素时,只需要插入value即可,不需要构造键值对
- set中的元素不可以重复(因此可以使用set进行去重)
- 使用set的迭代器遍历set中的元素,可以得到有序序列
- set中的元素默认按照小于来比较
- set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n
- set中的元素不允许修改
- set中的底层使用二叉搜索树(红黑树)来实现
🎈multiset的概念
概念:multiset 是 C++ 标准库 中的一个容器,它允许存储重复的元素。与 set 不同,set 中的元素是唯一的,而 multiset 中的元素可以重复
它与
set唯一不同的一点就是multiset中的元素可以重复
简单演示一下差别
int main()
{int arr[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 };// 注意:multiset在底层实际存储的是<int, int>的键值对multiset<int> s(arr, arr + sizeof(arr)/sizeof(arr[0]));for (auto& e : s){cout << e << " ";}cout << endl;return 0;
}
🧩set的使用
🌈set的模板参数列表

- T: set中存放元素的类型,实际在底层存储<value, value>的键值对
- Compare:set中元素默认按照小于来比较
- Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
🌞set的构造
| 函数声明 | 功能介绍 |
|---|---|
| set (const Compare& comp = Compare(), const Allocator&= Allocator() ) | 构造空的set |
| set (InputIterator first, InputIterator last, constCompare& comp = Compare(), const Allocator& =Allocator() ) | 用[first, last)区间中的元素构造set |
| set ( const set<Key,Compare,Allocator>& x) | set的拷贝构造 |
构造代码实现(示例):
int main()
{vector<int> v = { 1,5,7,6,3,4,5 };set<int> s1; // 构造空的set// 用[first, last)区间中的元素构造setset<int> s2(v.begin(),v.end()); set<int> s3(s2); // set的拷贝构造return 0;
}
🌙set的迭代器
set的迭代器有点多,其中包括正向迭代器,反向迭代器;const迭代器与非const迭代器
| 函数声明 | 功能介绍 |
|---|---|
| iterator begin() | 返回set中起始位置元素的迭代器 |
| iterator end() | 返回set中最后一个元素后面的迭代器 |
| const_iterator cbegin() const | 返回set中起始位置元素的const迭代器 |
| const_iterator cend() | const 返回set中最后一个元素后面的const迭代器 |
| reverse_iterator rbegin() | 返回set第一个元素的反向迭代器,即end |
| reverse_iterator rend() | 返回set最后一个元素下一个位置的反向迭代器,即rbegin |
| const_reverse_iterator crbegin() const | 返回set第一个元素的反向const迭代器,即cend |
| const_reverse_iterator crend() const | 返回set最后一个元素下一个位置的反向const迭代器,即crbegin |
因而有迭代器的存在,set可以跟方便的遍历整个结构
迭代器实现(示例):
int main()
{vector<int> v = { 1,5,7,6,3,4,5 };set<int> s1;set<int> s2(v.begin(),v.end());set<int> s3(s2);// 输出s2的遍历结果auto it = s2.begin();while (it != s2.end()){cout << *it << " "; // 1 3 4 5 6 7it++;}return 0;
}
⭐set的其他函数操作
| 函数声明 | 功能介绍 |
|---|---|
| pair<iterator,bool> insert (const value_type& x ) | 在set中插入元素x,实际插入的是<x, x>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,如果插入失败,说明x在set中已经存在,返回<x在set中的位置,false> |
| void erase ( iterator position ) | 删除set中position位置上的元素 |
| size_type erase ( const key_type& x ) | 删除set中值为x的元素,返回删除的元素的个数 |
| void erase ( iterator first,iterator last ) | 删除set中[first, last)区间中的元素 |
| void swap (set<Key,Compare,Allocator>&st ); | 交换set中的元素 |
| void clear ( ) | 将set中的元素清空 |
| iterator find ( const key_type& x ) const | 返回set中值为x的元素的位置 |
| size_type count ( const key_type& x ) | const 返回set中值为x的元素的个数 |
在set的这些函数中,用的最多的就是insert,find,erase

首先
insert一般是直接插入元素,或者是一段迭代器区间,在直接插入一个元素时,它的返回值是pair
- 当插入成功时,
first返回新位置的迭代器,然后second返回true;- 当set中已经存在该元素时,插入失败,
first返回已有元素位置的迭代器,然后second返回false

find不用多说,在set中是找到则返回该位置迭代器- 在
multiset中是返回第一个该元素位置的迭代器

erase在set中主要的作用就是删除该迭代器位置的元素,或者删除迭代器区间第二种用法是针对
multiset的,multiset可以有重复元素,因此可以返回删除元素的个数


这里介绍两个没有见过的函数
upper_bound,lower_bound
- lower_bound:返回>=该值元素位置的迭代器
- upper_bound:返回>该值元素位置的迭代器
这两个函数通常可以和erase结合使用删除一段迭代器区间
📚5. map 与 multimap
🎩map的概念
概念: map 是 C++ 标准库中的一个关联容器,它存储的元素都是键值对(key-value pairs),并且键(key)是唯一的。在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
typedef pair<const key, T> value_type;
map支持下标访问符,即在[]中放入key,就可以找到与key对应的valuemap通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))
🎈multimap的概念
概念: multimap 是 C++ 标准库
multimap中的接口可以参考map,功能都是类似的。
注意:
- multimap中的key是可以重复的
- multimap中的元素默认将key按照小于来比较
- multimap中没有重载
operator[]操作
🧩map的使用
🌈map的模板参数说明

- key: 键值对中key的类型
- T: 键值对中value的类型
- Compare: 比较器的类型,默认按小于比较
🌞map的构造
| 函数声明 | 功能介绍 |
|---|---|
| map() | 构造一个空的map |
int main()
{map<string,string>(); // 构造一个空的mapreturn 0;
}
🌙map的迭代器
| 函数声明 | 功能介绍 |
|---|---|
| begin()和end() | begin:首元素的位置,end最后一个元素的下一个位置 |
| cbegin()和cend() | 与begin和end意义相同,但cbegin和cend所指向的元素不能修改 |
| rbegin()和rend() | 反向迭代器,rbegin在end位置,rend在begin位置,其++和–操作与begin和end操作移动相反 |
| crbegin()和crend() | 与rbegin和rend位置相同,操作相同,但crbegin和crend所指向的元素不能修改 |
⭐map的其他函数操作
| 函数声明 | 功能简介 |
|---|---|
| pair<iterator,bool> insert (const value_type& x ) | 在map中插入键值对x,注意x是一个键值对,返回值也是键值对:iterator代表新插入元素的位置,bool代表释放插入成功 |
| size_type erase ( constkey_type& x ) | 删除键值为x的元素 |
| void erase ( iterator first,iterator last ) | 删除[first, last)区间中的元素 |
| iterator find ( const key_type& x) | 在map中插入key为x的元素,找到返回该元素的位置的迭代器,否则返回end |
| const_iterator find ( const key_type& x ) const | 在map中插入key为x的元素,找到返回该元素的位置的const迭代器,否则返回cend |
| mapped_type& operator[ ] (constkey_type& k) | 返回去key对应的value |
insert

在insert插入中,所需要的元素类型是value_type - > pair
map的成员类型


pair可以支持带参构造,无参构造和拷贝构造
map插入代码演示:
int main()
{map<string,string> d;d.insert(pair<string, string>("insert", "插入"));d.insert(pair<const char*, const char*>("find", "查找"));return 0;
}
而一般我们并不会这没写,因为有make_pair的存在,我们往往使用make_pair


make_pair是一个函数模板,他可以自己推演类型
int main()
{map<string,string> d;d.insert(make_pair("erase", "删除"));return 0;
}
operator[ ]


insert:插入成功 pair<新插入key所在节点的iterator, true>插入失败 pair<已经存在的key所在节点的iterator,false>
在使用operator[ ]时,它会自动插入一个元素,在插入成功时,返回该位置的second(默认为0),在插入失败时,它就会返回已有位置的second
📖6. 总结拓展
💧在实际中的应用
这里推荐两个题目让大家巩固set与map
前K个高频单词
两个数组的交集
🔥总结
随着我们深入探讨STL(Standard Template Library)中的map和set,我们不难发现,这两个容器类型在C++编程中扮演着举足轻重的角色。它们不仅提供了高效的数据存储和检索机制,还通过其独特的性质解决了许多实际问题
在学习的过程中,我们领略了
map如何以键值对的形式存储数据,并通过键来快速检索值。而set则以其独特的元素唯一性特点,为我们提供了一种确保集合中元素不重复的方法,然而学习之路永无止境。对于map和set的理解和应用,仅仅停留在基本的使用层面是远远不够的。我们需要进一步探索它们的高级用法
学习STL中的容器并不仅仅是为了掌握它们的使用方法。更重要的是,我们要学会如何根据问题的需求选择合适的容器类型,以及如何优化我们的代码以提高程序的性能和可维护性。在这个过程中,我们将会逐渐领悟到编程的精髓和乐趣,让我们一起在学习的道路上不断前行!

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

相关文章:
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:初步了解 二叉搜索树 🌹🌹期待您的关注 🌹🌹 ❀map与set 📒1.…...
cd 命令特殊路径符 mkdir命令
cd 特殊路径符 cd . 表示当前目录,比如 cd ./Desktop表示切换到当前目录下的Desktop目录内,和 cd Desktop效果一致。cd … 表示上一级目录,比如 cd … 即可切换到上一级目录,cd…/…切换到上二级目录。cd ~ 表示 HOME 目录&#…...
Mongodb UPDATE, 使用$position指定向数组中插入新元素的位置
学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第72篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关…...
【Kafka】Kafka Broker工作流程、节点服役与退役、副本、文件存储、高效读写数据-08
【Kafka】Kafka Broker工作流程、节点服役与退役、副本、文件存储、高效读写数据 1. Kafka Broker 工作流程1.1 Zookeeper 存储的 Kafka 信息1.2 Kafka Broker总体工作流程1.2.1 Controller介绍 1.3 Broker 重要参数 2. 节点服役与退役3. Kafka副本 1. Kafka Broker 工作流程 …...
如何恢复未格式化分区数据?看这里!
什么是未格式化分区? 未格式化或RAW文件系统的分区无法被Windows操作系统识别和挂载,因此,Windows会提示你进行格式化以创建新的文件系统。注意,不要进行格式化。通常,文件系统变为未格式化或RAW会出现以下常见错误消…...
通过“BOSS”精通比特币,深入认识私钥、账户和钱包
来源:币界原创 作者:636Marx 无论当今数字货币技术如何发展,认识区块链技术幕后的关键机制至关重要。无论您是新手还是经验丰富的数字货币从业者,掌握钱包地址、公钥和私钥的复杂性都有无可替代重要性。进入 BOSS Wallet,这是一款尖端的 Web…...
进程与线程的区别
进程(Process) 1:进程是操作系统分配资源的基本单位 2:每个进程都有自己独立的虚拟地址空间,虚拟地址空间映射真实物理地址 3:进程之间相互隔离,某一个进程的崩溃不会影响到其它进程 4&…...
【AI基础】第五步:纯天然保姆喂饭级-安装并运行chatglm3-6b
类似于 【AI基础】第三步:纯天然保姆喂饭级-安装并运行chatglm2-6b,有一些细节不一样。 此系列文章列表: 【AI基础】概览 【AI基础】第一步:安装python开发环境-windows篇_下载安装ai环境python 【AI基础】第一步:安装…...
【学习笔记】Elastic-Job和Quartz 实现企业级定时任务
Elastic-Job和Quartz 实现企业级定时任务 知识拆解框架整合Java高级玩法定时任务案例 第1章 课程介绍 课程的总体介绍,定时任务的应用场景和发展趋势,以及分布式走时任务的介绍 1-1、导学 1-2、为什么学习定时任务 1-3、定时任务技术发展趋势 1-4、主…...
舒适佩戴,享受沉浸式音乐体验,西圣AVA2耳机体验
平时不管是听音乐,还是打电话,戴上一副耳机都可以让我们获得更好的隐私性,并且在公共场所,比如办公室、车厢里,也可以获得属于自己的空间。现在市面上耳机的选择非常多,音质、续航和佩戴的舒适度是我们选择…...
c++学习-----内存管理
1. C/C内存分布 我们先来看下面的一段代码和相关问题 答案揭晓: 这里很多人会误认为*char2在常量区,这其实是错误的 因为: 首先在内存字符常量区分配一块内存空间放下”abcd\0”,然后在栈中分配一块连续的内存空间,…...
可视化数据科学平台在信贷领域应用系列七:自动机器学习(下篇)
在当今金融科技迅速发展的时代,自动机器学习(AutoML)逐步成为了信贷风控领域的重要工具。随着大数据和人工智能技术的进步以及信贷风险环境的快速变化,传统人工建模模式的时效性已经难以应对复杂多变的挑战。自动机器学习框架将数…...
OpenGL Super Bible 7th-Primitives, Pipelines, and Pixels图元、渲染管线与像素
简介 本文的原版为《OpenGL Super Bible 7th》,是同事给我的,翻译是原文+译文的形势。文章不属于机器直译,原因在于语言不存在一一对应的关系,我将尽可能的按照中国人看起来舒服的方式来翻译这些段子,如果段子让你感到身心愉悦,那还劳烦点个关注,追个更。如果我没有及时…...
SpringBoot3.0更新后,IDEA创建SpringBoot2.x项目
首先创建新项目 然后Next Type选图中对应的即可,先在这里选择JavaVersion为17,然后等会去修改这个jdk的版本,然后Next 在选择springboot版本时发现还是没有2.x的版本,继续选择一个没有后缀名的版本先,这里选择3.3.0,至…...
Linux开发讲课8--- linux的5种IO模型
一、这里IO是什么 操作系统为了保护自己,设计了用户态、内核态两个状态。应用程序一般工作在用户态,当调用一些底层操作的时候(比如 IO 操作),就需要切换到内核态才可以进行 服务器从网络接收的大致流程如下࿱…...
什么是云主机?
云主机是新一代的主机租借服务,它整合了高性能服务器与优质网络带宽,有用处理了传统主机租借价格偏高、服务品良莠不齐等缺陷,可全面满意中小企业、个人站长用户对主机租借服务低本钱,高牢靠,易办理的需求。 关于大…...
力扣上的经典问题:接雨水
力扣上的经典问题:接雨水 在众多的编程题库中,力扣(LeetCode)是一个非常受欢迎的平台,拥有大量的算法和数据结构练习题。其中,接雨水(Trapping Rain Water)问题因其巧妙的思路和广泛…...
双例集合(二)——双例集合的实现类之HashMap容器类
双例集合的常用实现类有HashMap和TreeMap两个,通过这两个类我们可以实现Map接口定义的容器,一般情况下使用HashMap容器类较多。 HashMap容器类是Map接口最常用的实现类,它的底层采用Hash算法来实现,这也就满足了键key不能重复的要…...
oracle-定时器(job)
--1分钟运行一次定时任务。sysdate为了定时任务即可生效。 DECLARE JOB NUMBER; BEGIN DBMS_JOB.SUBMIT(JOB,P_HJZ_HJZ_PJ_DDYTKAPB_INIT_JOB;,SYSDATE,sysdate1/24/60); COMMIT; END; / select * from user_jobs; --删除 begin DBMS_JOB.broken (462, false); DBM…...
cron.timezone
系统 date 数据库 show timezone插件 show cron.timezonealter system set cron.timezonePRC;show cron.timezone...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...
