《深入解析C++中的Map容器:键值对存储的终极指南》_c++ map实现原理
前引: 在C++编程中,高效管理数据是提升代码性能的关键。
std::map
作为标准模板库(STL)的核心容器之一,提供了一种基于红黑树的有序键值对存储机制,能够实现快速的查找、插入和删除操作。无论是构建配置系统、实现缓存机制,还是处理复杂的数据映射,掌握map
都能显著优化你的程序效率。本文将带你一步步探索map
的基本概念、核心操作、常见应用场景以及性能优化技巧,帮助你从新手快速进阶为实战高手。准备好开启这段高效编程之旅了吗?让我们开始吧!(map的重点:operator【】+ 插入)
目录
【一】map介绍
【二】主要特点
(1)有序存储
(2)键的唯一性
(3)动态大小
(4)迭代器支持
【三】接口学习
(1)默认构造
(2)插入(重点)
(1)间接创建类模板插入
(2)直接使用类模板插入
(3)使用函数模板插入
(4)多参构造隐式转换
(3)迭代器访问
(4)operator 【】(重点)
(1)引入
(2)operator【】
(3)原理剖析
(4)operator【】的运用
【一】map介绍
std::map
是一个关联容器,用于存储键值对(key-value pairs)。它基于红黑树(一种自平衡二叉搜索树)实现,确保元素按键的有序性!
(1)map
存储唯一的键(key)和对应的值(value)。键用于索引值,键必须是唯一的(如果插入重复键,新值会覆盖旧值)(2)元素按键的升序自动排序
(3)需要包含头文件
通俗理解:一个存储映射关系(键-值)数据的关联容器,它需要两个数据类型进行实例化
【二】主要特点
(1)有序存储
元素始终按键排序,遍历时按顺序输出
例如:插入键为 3、1、2 的元素,遍历输出顺序为 1、2、3
(2)键的唯一性
每个键在 map 中是唯一的,如果尝试插入相同的键,会覆盖之前的值
insert 插入相同的键会失败
operator[ ]会进行覆盖
(3)动态大小
自动调整存储空间,无需手动管理
(4)迭代器支持
支持双向(正向 反向)迭代器
【三】接口学习
(1)默认构造
只需要两个数据类型(内置类型、容器类型、自定义类型均可)和变量名即可实例化
map V1;map V2;map V3;
(2)插入(重点)
map 的插入不同于以往学习的所有容器的操作:每次插入都涉及到 pair 的使用
原因:这种关联映射型的容器存储,需要 pair(类模板)或者 make_pair(函数模板)提供 一种安全、高效的封装方式,可以将 key 和 value合二为一成一个对象!
pair
:是存储键值对的类型,需要显式指定类型make_pair
:是创建pair
对象的辅助函数,自动推断类型,简化代码
- 第一个成员(通常命名为
first
)键(key),类型为const Key
(键在map中不可改)- 第二个成员(通常命名为
second
)值(value),类型为T
(值可以修改)
(1)间接创建类模板插入
map V1;//单独创建pair插入pair K1(\"小明\", \"大学生\");V1.insert(K1);
(2)直接使用类模板插入
//直接使用pair插入V1.insert(pair(\"小王\", \"老师\"));
(3)使用函数模板插入
//使用函数模板插入V1.insert(make_pair(\"小白\", \"对象\"));
(4)多参构造隐式转换
/多参构造隐式转换V1.insert({ \"小二\",\"服务员\" });
(3)迭代器访问
我们知道不管是 pair 还是 make_pair 为了高效、方便,将 key 和 value 合二为一转为一个对象
既然插入的是一个 pair 对象,那么访问数据也应该拿到是 pair 类型,所以我们需要分别打印:
map::iterator it = V1.begin();while (it != V1.end()){cout << (*it).first << \" \" << (*it).second << endl;//或者//cout <first << \" \" <second << endl;it++;}
(4)operator 【】(重点)
(1)引入
如下假如现在有几个字符串,我们需要统计每种字符串出现的个数:
string arr[] = { \"西瓜\",\"黄瓜\",\"哈密瓜\",\"哈密瓜\",\"西瓜\" };
如果用 map 的思维,我们可以这么写:
for (const auto& e : arr){//先看这个字符串是否已经存在auto it = V.find(e);//如果不存在if (it == V.end()){//插入V.insert(make_pair(e, 1));}else{it->second++;}}
效果展示:
(2)operator【】
如果我们用 operator[ ]可以简写为:
这是为何?下面我们开始原理剖析
(3)原理剖析
首先我们看 【】的设定:
可以看到它的底层是 insert ,那么我们看看 insert 的返回值:
这里就不去繁琐的推论了,我们直接说结论:
(1)首先operator【】接收 key 会先调用 insert 进行插入 pair,这里的 value 给 的是缺省值,比如 int 类型的缺省为0
(2)bool会根据是否已经存在 key 接收true或者false
(3)将这个 key 和 value 利用打包成一个对象 pair
(4)最后返回这个插入/原来对象的 iterator->second,即这个对象的value
(4)operator【】的运用
V1.insert(make_pair(\"小一\", \"大学生\"));V1.insert(make_pair(\"小二\", \"老师\"));//查找+读cout << V1[\"小一\"] << endl;//插入V1[\"小三\"];//修改V1[\"小二\"] = \"对象\";//插入+修改V1[\"小四\"] = \"兄弟\";