前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++(STL):28 ---关联式容器map用法

C++(STL):28 ---关联式容器map用法

作者头像
用户3479834
发布于 2021-02-03 06:47:27
发布于 2021-02-03 06:47:27
1.1K00
代码可运行
举报
文章被收录于专栏:游戏开发司机游戏开发司机
运行总次数:0
代码可运行

作为关联式容器的一种,map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,包括 C++ 基本数据类型(int、double 等)、使用结构体或类自定义的类型。

通常情况下,map 容器中存储的各个键值对都选用 string 字符串作为键的类型。

与此同时,在使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认情况下,map 容器选用std::less<T>排序规则(其中 T 表示键的数据类型),其会根据键的大小对所有键值对做升序排序。当然,根据实际情况的需要,我们可以手动指定 map 容器的排序规则,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater<T>),也可以自定义排序规则。

关于如何自定义 map 容器的排序规则,后续章节会做详细讲解。

另外需要注意的是,使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改。换句话说,map 容器中存储的各个键值对不仅键的值独一无二,键的类型也会用 const 修饰,这意味着只要键值对被存储到 map 容器中,其键的值将不能再做任何修改。

前面提到,map 容器存储的都是 pair 类型的键值对元素,更确切的说,该容器存储的都是 pair<const K, T> 类型(其中 K 和 T 分别表示键和值的数据类型)的键值对元素。

map 容器定义在 <map> 头文件中,并位于 std 命名空间中。因此,如果想使用 map 容器,代码中应包含如下语句:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <map>
using namespace std;

注意,第二行代码不是必需的,如果不用,则后续程序中在使用 map 容器时,需手动注明 std 命名空间(强烈建议初学者使用)。

map 容器的模板定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template < class Key,      // 指定键(key)的类型
class T,                                       // 指定值(value)的类型
class Compare = less<Key>,                     // 指定排序规则
class Alloc = allocator<pair<const Key,T> >  // 指定分配器对象的类型
> class map;

可以看到,map 容器模板有 4 个参数,其中后 2 个参数都设有默认值。大多数场景中,我们只需要设定前 2 个参数的值,有些场景可能会用到第 3 个参数,但最后一个参数几乎不会用到。

创建C++ map容器的几种方法

map 容器的模板类中包含多种构造函数,因此创建 map 容器的方式也有多种,下面就几种常用的创建 map 容器的方法,做一一讲解。 1) 通过调用 map 容器类的默认构造函数,可以创建出一个空的 map 容器,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>myMap;

如果程序中已经默认指定了 std 命令空间,这里可以省略 std::。

通过此方式创建出的 myMap 容器,初始状态下是空的,即没有存储任何键值对。鉴于空 map 容器可以根据需要随时添加新的键值对,因此创建空 map 容器是比较常用的。 2) 当然在创建 map 容器的同时,也可以进行初始化,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>myMap{ {"C语言教程",10},{"STL教程",20} };

由此,myMap 容器在初始状态下,就包含有 2 个键值对。 再次强调,map 容器中存储的键值对,其本质都是 pair 类模板创建的 pair 对象。因此,下面程序也可以创建出一模一样的 myMap 容器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>myMap{std::make_pair("C语言教程",10),std::make_pair("STL教程",20)};

3) 除此之外,在某些场景中,可以利用先前已创建好的 map 容器,再创建一个新的 map 容器。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>newMap(myMap);

由此,通过调用 map 容器的拷贝(复制)构造函数,即可成功创建一个和 myMap 完全一样的 newMap 容器。 C++ 11 标准中,还为 map 容器增添了移动构造函数。当有临时的 map 对象作为参数,传递给要初始化的 map 容器时,此时就会调用移动构造函数。举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//#创建一个会返回临时 map 对象的函数
std::map<std::string,int> disMap() {
std::map<std::string, int>tempMap{ {"C语言教程",10},{"STL教程",20} };
return tempMap;
}
//调用 map 类模板的移动构造函数创建 newMap 容器
std::map<std::string, int>newMap(disMap());

注意,无论是调用复制构造函数还是调用拷贝构造函数,都必须保证这 2 个容器的类型完全一致。

4) map 类模板还支持取已建 map 容器中指定区域内的键值对,创建并初始化新的 map 容器。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>myMap{ {"高司机",10},{"司机高",20} };
std::map<std::string, int>newMap(++myMap.begin(), myMap.end());

这里,通过调用 map 容器的双向迭代器,实现了在创建 newMap 容器的同时,将其初始化为包含一个 {"STL教程",20} 键值对的容器。

有关 map 容器迭代器,后续章节会做详细讲解。

5) 当然,在以上几种创建 map 容器的基础上,我们都可以手动修改 map 容器的排序规则。默认情况下,map 容器调用 std::less<T> 规则,根据容器内各键值对的键的大小,对所有键值对做升序排序。 因此,如下 2 行创建 map 容器的方式,其实是等价的:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int>myMap{ {"C语言教程",10},{"STL教程",20} };
std::map<std::string, int, std::less<std::string> >myMap{ {"C语言教程",10},{"STL教程",20} };
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
以上 2 中创建方式生成的 myMap 容器,其内部键值对排列的顺序为:

<"C语言教程", 10> <"STL教程", 20>

下面程序手动修改了 myMap 容器的排序规则,令其作降序排序:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::map<std::string, int, std::greater<std::string> >myMap{ {"C语言教程",10},{"STL教程",20} };
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
此时,myMap 容器内部键值对排列的顺序为:

<"STL教程", 20> <"C语言教程", 10>

在某些特定场景中,我们还需要为 map 容器自定义排序规则,此部分知识后续将利用整整一节做重点讲解。

C++ map容器包含的成员方法

表 1 列出了 map 容器提供的常用成员方法以及各自的功能。

成员方法

功能

begin()

返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

end()

返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

rbegin()

返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。

rend()

返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。

cbegin()

和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。

cend()

和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。

crbegin()

和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。

crend()

和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。

find(key)

在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

lower_bound(key)

返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

upper_bound(key)

返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

equal_range(key)

该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。

empty()

若容器为空,则返回 true;否则 false。

size()

返回当前 map 容器中存有键值对的个数。

max_size()

返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。

operator[]

map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值,就可以向获取数组中元素那样,通过键直接获取对应的值。

at(key)

找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常。

insert()

向 map 容器中插入键值对。

erase()

删除 map 容器指定位置、指定键(key)值或者指定区域内的键值对。后续章节还会对该方法做重点讲解。

swap()

交换 2 个 map 容器中存储的键值对,这意味着,操作的 2 个键值对的类型必须相同。

clear()

清空 map 容器中所有的键值对,即使 map 容器的 size() 为 0。

emplace()

在当前 map 容器中的指定位置处构造新键值对。其效果和插入键值对一样,但效率更高。

emplace_hint()

在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。

count(key)

在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。

下面的样例演示了表 1 中部分成员方法的用法:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <map>      // map
#include <string>       // string
using namespace std;


int main() {
//创建空 map 容器,默认根据个键值对中键的值,对键值对做降序排序
std::map<std::string, std::string, std::greater<std::string>>myMap;
//调用 emplace() 方法,直接向 myMap 容器中指定位置构造新键值对
myMap.emplace("高司机","gaosiji");
myMap.emplace("司机高", "sijigao"); 
//输出当前 myMap 容器存储键值对的个数
cout << "myMap size==" << myMap.size() << endl;
//判断当前 myMap 容器是否为空
if (!myMap.empty()) {
//借助 myMap 容器迭代器,将该容器的键值对逐个输出
for (auto i = myMap.begin(); i != myMap.end(); ++i) {
cout << i->first << " " << i->second << endl;
}
}
return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 游戏开发司机 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
MyEMS开源系统安装之龙蜥(Anolis) OS 下
龙蜥(Anolis)OS 上(https://cloud.tencent.com/developer/article/write/2520175)
开源能源管理系统
2025/05/14
680
MyEMS开源系统安装(三)CentOS/RHEL/Rocky/AlmaLinux/Oracle Linux服务器介绍
参考 http://nginx.org/en/linux_packages.html#RHEL
开源能源管理系统
2025/05/13
710
MyEMS开源系统安装(五)Docker Compose
假定的主机IP为 192.168.0.1,数据库IP为 192.168.0.2,数据库账号为:root,数据库密码:!MyEMS1,请酌情修改
开源能源管理系统
2025/05/14
980
如何在宝塔Linux面板上安装MyEMS
脚本:wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh ed8484bec
开源能源管理系统
2025/05/14
570
Linux上的Podman
为多个平台构建,而不仅仅是为当前用户运行的体系结构和操作系统构建。 您可以使用buildx并设置--platform标志来指定构建输出的目标平台(例如,linux/amd64、linux/arm64或darwin/amd64)。
开源能源管理系统
2025/05/23
870
MyEMS开源系统安装之龙蜥(Anolis) OS 上
检查或更改myems-api.service和myems-api.socket中的侦听端口(默认值为8000):
开源能源管理系统
2025/05/14
390
MyEMS开源能源管理系统v5.5.0发布通知
MyEMS开源能源管理系统(EMS)参考ISO 50001能源管理体系标准(等同GB/T 23331-2020),适用于建筑、工厂、商场、医院、园区、能碳管理中心的电、水、气、冷、热等能源数据采集、分析、报表,还有光伏、储能、充电桩、微电网、虚拟电厂、设备控制、故障诊断、工单管理、人工智能优化等企业版可选功能。资深专业公司开发维护,保障长期支持。用开源助力企业集团、产业园区、能源运营商低碳发展!
开源能源管理系统
2025/05/30
550
MyEMS开源能源管理系统v5.5.0发布通知
如何在树莓派上安装MyEMS开源能源管理系统(下)
为了避免 'error: externally-managed-environment', 创建一个虚拟环境配置目录:
开源能源管理系统
2025/05/14
750
如何在树莓派上安装MyEMS开源能源管理系统(上)
默认情况下,MySQL安装时没有设置任何密码,这意味着您无需任何身份验证即可访问MySQL服务器。运行以下命令以开始MySQL保护过程。
开源能源管理系统
2025/05/13
660
升级MyEMS开源能源系统
开源能源管理系统
2025/05/23
250
MyEMS的安装部署与数据读取查看
mysql -u root -p < myems_billing_baseline_db.sql
用户10891665
2023/12/24
1K0
MyEMS开源能源管理系统核心代码解读015
MyEMS开源能源管理系统适用于建筑、工厂、商场、医院、园区的电、水、气等能源数据采集、分析、报表,还有光伏、储能、充电桩、微电网、设备控制、故障诊断、工单管理、人工智能优化等可选功能。资深专业团队开发维护,保障长期支持。用开源助力企业集团、产业园区、能源运营商低碳发展!
开源能源管理系统
2025/05/27
680
MyEMS开源能源管理系统核心代码解读014
MyEMS开源能源管理系统适用于建筑、工厂、商场、医院、园区的电、水、气等能源数据采集、分析、报表,还有光伏、储能、充电桩、微电网、设备控制、故障诊断、工单管理、人工智能优化等可选功能。资深专业团队开发维护,保障长期支持。用开源助力企业集团、产业园区、能源运营商低碳发展!
开源能源管理系统
2025/05/26
580
MyEMS开源系统安装(一)安装数据库
在MySQL命令行中执行以下脚本,或在其他MySQL客户端工具中执行,如MySQL Workbench、Navicat、DBaver、phpMyAdmin等。
开源能源管理系统
2025/05/13
960
Linux搭建开源企业邮箱系统EwoMail
EwoMail是基于Linux的开源邮件服务器软件,集成了众多优秀稳定的组件,是一个快速部署、简单高效、多语言、安全稳定的邮件解决方案,帮助你提升运维效率,降低 IT 成本,兼容主流的邮件客户端,同时支持电脑和手机邮件客户端。
星哥玩云
2022/06/09
4.5K0
Linux搭建开源企业邮箱系统EwoMail
CentOS 7下安装Logstash ELK Stack 日志管理系统(下)
修改防火墙,对外开放tcp/5601 [root@elk elk]# firewall-cmd --permanent --add-port=5601/tcp Success [root@elk elk]# firewall-cmd --reload success [root@elk elk]# firewall-cmd --list-all public (default, active) interfaces: eno16777984 eno33557248 sources: servic
小小科
2018/05/04
1K0
CentOS 7下安装Logstash ELK Stack 日志管理系统(下)
开源日志平台GrayLog最新版本6.1.0的一键安装脚本
将如下脚本与压缩包上传到AlmaLinux9.X或RockyLinux9.X系统的同一个目录下GrayLog6.1.0_MongoDB6.0_OpenSearch2.15.0_EL9_RPM.tar.gzGrayLogServer6.1.0_EL9_install.sh
yuanfan2012
2024/10/23
9462
开源日志平台GrayLog最新版本6.1.0的一键安装脚本
frp 内网穿透含web和ssh(已验证)
用公司内网的服务器,或者公司的电脑搭建了一个web站点,却无法在外网访问web站点,或者在家想用ssh连接公司的内网服务器。frp就是如何利用内网穿透的方式实现以上功能。
用户10002156
2023/08/07
1.4K0
frp 内网穿透含web和ssh(已验证)
Nginx安装与代理
将80转发至8082端口:例如:发布访问地址192.168.00.000:8082,转发之后可直接访问192.168.00.000
小世界的野孩子
2019/09/11
3660
安利一款免费、开源、实时的服务器监控工具:Netdata
Netdata 是一个免费、开源、实时的服务器监控工具,可以可视化和监控实时数据,如 CPU 使用率、RAM 使用率、负载、SWAP 使用率、带宽使用率、磁盘使用率等。它可以帮助系统管理员了解您的系统或应用程序中正在发生的事情以及刚刚发生的事情。它可以安装在任何物理服务器、虚拟机、容器和物联网设备上。它提供了一个交互式 Web 界面来查看您的服务器指标,并支持用于持久存储的各种数据存储。
全栈程序员站长
2022/08/24
1.9K0
安利一款免费、开源、实时的服务器监控工具:Netdata
推荐阅读
相关推荐
MyEMS开源系统安装之龙蜥(Anolis) OS 下
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档