C++STL——map/multimap容器详解

news2024/11/18 23:35:48

在这里插入图片描述纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。

💬文章目录

    • 一.对组(pair)
    • 二.map/multimap基本概念
    • 三.map容器常用操作
      • ①map构造函数
      • ②map迭代器获取
      • ③map赋值操作
      • ④map大小操作
      • ⑤map插入数据元素操作(重点)
      • ⑥元素操作
      • ⑦map删除操作
      • ⑧map查找操作

一.对组(pair)

在STL中有些容器的元素是一种叫pair的数据结构。

对组(pair)是类模板,对组(pair)将一对值组合成一个值,一般用于表示key/value数据,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second访问。其实现是结构体。

什么是key/value?
在日常生活中,有很多数据集,不管什么样的数据集都可以用key/value表示,key也叫键值,value也叫实值

  • 例如:QQ号是key,生日年龄等级昵称都是value。
    在这里插入图片描述
  • 全国人口数据,身份证号是key,性别出生日期都是value
    在这里插入图片描述

key的特点是不会重复,我们的QQ号身份证号肯定不会重复,value可以是一个数据项也可以是多个数据项。

pair结构模板的定义如下:

template <class T1, class T2>
struct pair 
{ 
    T1 first;     // 第一个成员,一般表示key。
    T2 second;  // 第二个成员,一般表示value。
	pair();       // 默认构造函数。
	pair(const T1 &val1,const T2 &val2);   // 有两个参数的构造函数。
	pair(const pair<T1,T2> &p);           // 拷贝构造函数。
	void swap(pair<T1,T2> &p);           // 交换两个pair。
};

make_pair函数模板的定义如下:

template <class T1, class T2>
make_pair(const T1 &first,const T2 &second)
{
	return pair<T1,T2>(first, second);
}

实例:对组pair的使用

#include <iostream>
using namespace std;
void test()
{
	//第一种方法创建一个对组
	pair<string, int> pair1(string("强风吹拂"), 20); // 有两个参数的构造函数。
	cout << pair1.first << endl; //访问pair第一个值
	cout << pair1.second << endl;//访问pair第二个值
	//第二种
	pair<string, int> pair2 = make_pair("king", 20);//make_pair函数创建pair对组,make_pair会返回一个临时的pair
	cout << pair2.first << endl;
	cout << pair2.second << endl;
	//pair=赋值
	pair<string, int> pair3 = pair2;
	cout << pair3.first << endl;
	cout << pair3.second << endl;
}
int main()
{
	test();
	return 0;
}

运行结果:
在这里插入图片描述

二.map/multimap基本概念

map的特性是,所有元素都会根据元素的键值key自动排序。map所有的元素都是pair,同时拥有键值key和实值value,pair的第一元素被视为键值key,第二元素被视为实值value,map不允许两个元素有相同的键值。map和multimap都都封装了红黑树(平衡排序二叉树),用于查找。
在这里插入图片描述

map容器的迭代器:
红黑树采用二叉链表实现,所以map能提供了双向迭代器。

二叉链表:                               
struct BTNode                        
{                                  
   	pair<K,V> p;       // 键值对。      
	BTNode *parent;   // 父节点。   
	BTNode *lchirld;    // 左子树。 
	BTNode *rchild;    // 右子树。 
};                           

我们可以通过map的迭代器改变map的键值吗?答案是不行,因为map的键值关系到map元素的排列规则,任意改变map键值将会严重破坏map组织。如果想要修改元素的实值,那么是可以的。
multimap和map的操作类似,唯一区别multimap键值可重复。
map类模板的声明:

template <class K, class V, class P = less<K>, class _Alloc = allocator<pair<const K, V >>>
class map : public _Tree<_Tmap_traits< K, V, P, _Alloc, false>> 
{}

  • 第一个模板参数K:key的数据类型(pair.first)。
  • 第二个模板参数V:value的数据类型(pair.second)。
  • 第三个模板参数P:排序方法,缺省按less升序。
  • 第四个模板参数_Alloc:分配器,缺省用new和delete。

三.map容器常用操作

①map构造函数

注:使用map/multimap容器时,需包含头文件#include <map>
关于构造函数,我们只要知道如何创建一个空的map容器即可,然后往容器中插入数据。插入数据的方法在后面演示。

函数原型解释
map<T1, T2> mapTT;map默认构造函数:,T1为key的数据类型,T2为value的数据类型
map<T1, T2>(const map &mp);拷贝构造函数,T1和T2应和mp相同。

②map迭代器获取

map能提供了双向迭代器。
在这里插入图片描述

获取正向迭代器iterator:

函数原型解释
iterator begin();返回指向开始位置的迭代器,iterator是正向迭代器。只能使用++运算符从左向右遍历容器,每次沿容器向右移动一个元素
const_iterator begin();返回指向开始位置并且为常量的迭代器
const_iterator cbegin();返回指向开始并且为常量的迭代器,const_iterator 常正向迭代器。函数作用:配合auto使用
iterator end();返回指向末尾元素的下一个位置的迭代器
const_iterator end();返回指向末尾元素的下一个位置并且为常量的迭代器
const_iterator cend();返回指向末尾元素的下一个位置的并且为常量的迭代器,函数作用:配合auto使用

获取反向迭代器reverse_iterator:

函数原型解释
reverse_iterator rbegin();返回反向迭代器,指向末尾元素下一个位置,操作都是往相反反向,reverse_iterator 为反向迭代器
const_reverse_iterator crbegin();返回反向迭代器,指向末尾元素下一个位置,操作都是往相反反向,并且为常量属性,const_reverse_iterator 常反向迭代器。
reverse_iterator rend();返回反向迭代器,指向开头元素的位置,操作都是往相反反向
const_reverse_iterator cre nd();返回反向迭代器,指向开头元素的位置,操作都是往相反反向,并且为常量属性

迭代器都可以进行++操作。反向迭代器和正向迭代器的区别在于:
对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素;
而对反向迭代器进行++操作时,迭代器会指向容器中的前一个元素。

注意:begin函数和cbegin函数都可以返回const_iterator,那么为什么要两个函数呢?
因为begin函数有重载,无法配合auto(自动推导数据类型)使用,所以才多出一个cbegin函数。

③map赋值操作

函数原型解释
map&operator=(const map &mp);重载等号操作符
swap(mp);交换两个集合容器

④map大小操作

函数原型解释
size();返回容器中元素的数目
empty();判断容器是否为空

⑤map插入数据元素操作(重点)

函数原型解释
void insert(…);用统一初始化列表在容器中插入多个元素。
pair<iterator,bool> insert(…);往容器插入一个元素,返回pair<iterator,bool>,pair.first是已插入元素的迭代器,pair.second是插入结果。
void insert(iterator first,iterator last);用迭代器插入一个区间的元素,有的可能成功,有的可能失败,所以返回值为void

实例:map插入数据元素操作

#include <iostream>
using namespace std;
#include <map>//包含头文件
void test()
{
	map<string, string> m;
	//void insert(……)函数举例,
	m.insert({ pair<string,string>("08","亚索"),make_pair("03", "瑟提"),map<string, string>::value_type("01","德莱文") ,{"04","卢锡安"} });
	//pair<iterator, bool> insert(…);函数举例

	map<string, string> m2;
	// 第一种 通过创建pair匿名对象的方式插入对象
	auto ret = m2.insert(pair<string, string>("12", "斯维因"));
	if (ret.second)
	{
		cout << "插入成功" << endl;
	}
	else
	{
		cout << "插入失败" << endl;
	}

	// 第二种 通过make_pair的方式插入对象,make_pair会返回一个临时对象
	m2.insert(make_pair("05", "皇子"));

	// 第三种 通过value_type的方式插入对象
	m2.insert(map<string, string>::value_type("14", "塞恩"));

	// 第四种 通过数组的方式插入值
	m2["09"] = "强风吹拂king";//[]中括号内是键值

	for (auto& val : m)
	{
		cout << val.first << "," << val.second << "  ";
	}
	cout << endl;
	for (auto& val : m2)
	{
		cout << val.first << "," << val.second << "  ";
	}
	cout << endl;
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

⑥元素操作

函数原型解释
operator[key];用给定的key访问元素。
at(key);用给定的key访问元素。

注意:
①[ ]运算符:如果指定键值不存在,会向容器中添加新的键值对,并且value为空。如果指定键值存在,则读取或修改容器中指定键的值。
②at()成员函数:如果指定键值不存在,不会向容器中添加新的键值对,而是直接抛出out_of_range 异常。

实例:元素操作

#include <iostream>
using namespace std;
#include <map>//包含头文件
void test()
{
	map<string, string> m({ { "08","亚索" }, { "03","伊泽瑞尔" }, { "01","寒冰" }, { "07","猪妹" }, { "05","德莱文" } });

	cout << "m[08]=" << m["08"] << endl; // 显示key为08的元素的value。
	cout << "m[09]=" << m["09"] << endl; // 显示key为09的元素的value。key为09的元素不存在,将添加新的键值对。并且value为空。
	m["09"] = "大头";
	m["07"] = "女皇"; // 把key为07的元素的value修改为女皇。
	m["12"] = "强风吹拂king";  // 通过[]将添加新的键值对。

	for (auto& val : m)
	{
		cout << val.first << "," << val.second << "  ";
	}
	cout << endl;
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

⑦map删除操作

函数原型解释
clear();删除所有元素
erase(pos);删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);删除容器中键值key为keyElem的对组。

⑧map查找操作

函数原型解释
find(key);查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
count(keyElem);返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是1。对multimap来说,值可能大于1。
lower_bound(keyElem);返回一个指向当前 map容器中第一个大于或等于keyElem 的元素的双向迭代器。如果 map容器用 const 限定,则该方法返回的是 const 类型的双向迭代器,若不存在,返回map.end();
upper_bound(keyElem);返回一个指向当前 map容器中第一个大于keyElem 的元素的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。若不存在,返回map.end();
equal_range(keyElem)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为keyElem 的元素(map容器中各个元素是唯一的,因此该范围最多包含一个元素)。若不存在,返回map.end();

实例:map查找操作

#include <iostream>
using namespace std;
#include <map>//包含头文件
void test()
{
	map<string, string> m({ { "08","亚索" }, { "03","伊泽瑞尔" }, { "01","寒冰" }, { "07","猪妹" }, { "05","德莱文" } });
	for (auto& val : m)
	cout << val.first << "," << val.second << "  ";
	cout << endl;

	// 在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。
	auto it1 = m.find("05");
	if (it1 != m.end())
	{
		cout << "查找成功:" << it1->first << "," << it1->second << endl;
	}
	else
	{
		cout << "查找失败。\n";
	}

	//lower_bound返回一个指向当前 map容器中第一个大于或等于keyElem 的元素的双向迭代器。
	//如果 map容器用 const 限定,则该方法返回的是 const 类型的双向迭代器若不存在,返回map.end();
	auto it2 = m.lower_bound("05");
	if (it2 != m.end())
	{
		cout << "lower_bound()查找成功:" << it2->first << "," << it2->second << endl;
	}
	else
	{
		cout << "lower_bound()查找失败。\n";
	}


	//upper_bound返回一个指向当前 map容器中第一个大于keyElem 的元素的迭代器。
	//如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。若不存在,返回map.end();
	auto it3 = m.upper_bound("05");
	if (it3 != m.end())
	{
		cout << "upper_bound()查找成功:" << it3->first << "," << it3->second << endl;
	}
	else
	{
		cout << "upper_bound()查找失败。\n";
	}


	//equal_range返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价
	// pair.second 和 upper_bound() 方法的返回值等价。若不存在,返回map.end();
	//返回大于等于05的两个最小的数的迭代器,如果有05那么就返回05的迭代器和大于05的最小数的迭代器
	//用对组的方式存储起来
	auto ret = m.equal_range("05");
	if(ret.first!=m.end())
	{
		cout << "equal_range查找成功:" << endl;
		cout << ret.first->first << ret.first->second << endl;
		cout << ret.second->first << ret.second->second << endl;
	}
	else
	{
		cout << "equal_range查找失败。\n";
	}

	//	统计map容器中键值为key的键值对的个数。
	cout << "count(05)=" << m.count("05") << endl;   // 返回1。
	cout << "count(06)=" << m.count("06") << endl;   // 返回0。
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/836828.html

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

相关文章

突破视觉边界:深入探索AI图像识别的现状与挑战

图像识别作为人工智能领域的一个重要研究方向&#xff0c;取得了许多令人瞩目的成就。深入探索当前AI图像识别技术的现状以及所面临的挑战&#xff0c;讨论各种方法的优势和局限性。 目录 引言1.1 AI图像识别的背景和概述1.2 人工智能在图像识别中的应用和重要性 图像识别基础知…

RISC-V基础指令之逻辑指令 and、or、xor、not

RISC-V的逻辑指令是用于对两个寄存器或一个寄存器和一个立即数进行按位的逻辑运算&#xff0c;并将结果存放在另一个寄存器中的指令。按位的逻辑运算就是把两个操作数的每一位分别进行相应的逻辑运算&#xff0c;得到一个新的位。RISC-V的逻辑指令有以下几种&#xff1a; and&…

c++高性能多进程 cuda编程:GPU结构和通信速度+tiling的代码实现

根据c高性能多进程 cuda编程:GPU结构和通信速度tiling的分析&#xff0c;依靠pytorch的JIT进行了实现&#xff0c;所以在安装pytorch的环境中&#xff0c;直接执行test.py就能直接运行。 代码结构如下&#xff0c;地址 mm.h void function_mm(float *c,const float *a,cons…

一文辨析,性能分析top命令中进程NI和PR

分析 Linux 服务器性能&#xff0c;首先想到的命令肯定是 top, 通过它&#xff0c;我们可以看到当前服务器资源使用情况和进程运行资源占用情况。 如果你想学习自动化测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B站播放全网第一的自动化测试教程&…

网络安全【黑客】自学

1.什么是网络安全&#xff1f; 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有…

MySql UNION 一行转多列

背景:DataEase饼图有特定格式&#xff0c;并且报表要求全部使用SQL语句获取数据 原先数据格式如下&#xff0c;需要行转换列 转换后结果&#xff1a; 原理 字段1&#xff0c;target作为一个不存在的字段&#xff0c;用于命名。 字段2&#xff0c;count字段是关键&#xff0c;…

Centos更换网卡名称为eth0

Centos更换网卡名称为eth0 已安装好系统后需要修改网卡名称为eth0 编辑配置文件将ens33信息替换为eth0,可在vim命令模式输入%s/ens33/eth0/g替换相关内容 修改内核文件,添加内容:net.ifnames=0 biosdevname=0 [root@nova3 ~]# vim /etc/default/grub 使用命令重新生成g…

高级IO:五种IO模型

五种IO模型 阻塞IO 阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式. 非阻塞IO 如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EAGAIN/EWOULDBLOCK错误码. 非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这…

无人驾驶实战-第六课(动态环境感知与Tracking)

跟踪是在连续帧中根据物体信息关联(确定)同一物体 运动模型(motion model)&#xff1a;根据历史的位置和速度 ( 大小和方向) 建立模型&#xff0c;预测当前帧中物体的大致位置 外观模型(appearance model)&#xff1a;根据历史外观&#xff08;颜色 尺寸 2D/3D框 轮廓等&#…

开发运营监控

DevOps 监控使管理员能够实时了解生产环境中的元素&#xff0c;并有助于确保应用程序平稳运行&#xff0c;同时提供最高的业务价值&#xff0c;对于采用 DevOps 文化和方法的公司来说&#xff0c;这一点至关重要。 什么是开发运营监控 DevOps 通过持续开发、集成、测试、监控…

如何将超大文件传输给别人,超大文件如何传输呢?

我们在日常生活和工作中&#xff0c;经常会遇到需要把超大文件发送给别人的情况。但是&#xff0c;在互联网发展如此迅速的今天&#xff0c;我们还有哪些方法可以快速地传输超大文件呢&#xff1f;超大文件应该怎样传输才能保证效率和安全呢&#xff1f;这些问题一直困扰着我们…

利用PostGIS自带工具导入shp数据

一、shapefile导入PostGIS 1、利用PostGIS自带工具导入 开始程序搜索如下工具 打开工具界面如下图&#xff0c;点击View conncetion details进行数据库连接&#xff0c;点击Add File进行Shapefile所在路径加载&#xff0c;点击Option进行编码设置&#xff0c;设置完成后点击Im…

mac录屏怎么打开?很简单,让我来教你!

mac电脑作为一款广受欢迎的电脑系统&#xff0c;提供了多种方式来满足用户录屏的需求。无论您是要录制教学视频、制作演示文稿&#xff0c;还是记录游戏精彩瞬间&#xff0c;mac电脑都能帮助您实现这些目标。本文将为您介绍两种mac录屏的方法。通过本文的指导&#xff0c;您将能…

8.4一日总结

1.远程仓库的提交方式(免密提交) a.ssh:隧道加密传输协议,一般用来登录远程服务器 b.使用 git clone 仓库名 配置(生成公私钥对) ssh-Keygen [-t rsa -C 邮箱地址] 通过执行上述命令,全程回车,就会在~/.ssh/id_rsa(私钥)和id_rsa.pub(公钥),私钥是必须要保存好的,并不能…

明白均线信号的投资者就知道如何交易

在Forexclub上的交易的投资者&#xff0c;都在使用5、25和50周期的均线来分析收盘价。其中&#xff0c;5周期的均线为红色&#xff0c;25和50周期的均线为黄色。同时使用抛物面SAR指标&#xff0c;保留其默认参数。 开立多头头寸的条件是&#xff1a;5周期的红色均线从下方突破…

身体原来是一份宝贵的“情绪地图”, 疾病都在教导我们如何与世界相处

当我们生病时 很多时候&#xff0c;是一个契机 让我们来倾听自己内心的压抑的真实 聆听身体的声音 身体能够教会我们如何对待情绪 进而教导我们如何与世界相处 -1- 身体上&#xff0c;有你的情绪地图 皮肤是身体的镜子&#xff0c;身体则是心灵的镜子。生病&#xff0c…

亿欧智库:2023中国功效型护肤产品成分解析研究报告(附下载

关于报告的所有内容&#xff0c;公众【营销人星球】获取下载查看 核心观点 消费端&#xff1a;“纯净美妆〞概念火热&#xff0c;消费驱动因素向成分来源硬核转变 新冠疫情过后&#xff0c;消费者对于生活健康&#xff1a;自然&#xff0c;可持续的关注度持续上升。在消费者…

【小吉带你学Git】idea操作(1)_配置环境并进行基本操作

&#x1f38a;专栏【Git】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;环境准备⭐配置Git忽略文件&#x1f384;方法&#x1f33a;创…

【音视频】edge与chrome在性能上的比较

目录 结论先说 实验 结论 实验机器的cpu配置 用EDGE拉九路​编辑 google拉五路就拉不出来了 资源使用情况 edge报错​编辑 结论先说 实验 用chrome先拉九路&#xff0c;再想用edge拉九路&#xff0c;发现拉五路后怎么也拉不出&#xff1b; 后面发现cpu爆满&#xff1b;切…

Intellij IDEA运行报Command line is too long的解决办法

想哭&#xff0c;vue前端运行起来&#xff0c;对应的后端也得起服务。 后端出的这个bug&#xff0c;下面的博客写的第二种方法&#xff0c;完整截图是下面这个。 ​​​​​​​​​​​​​​​​​​​​Intellij IDEA运行报Command line is too long的解决办法 - 知乎 (zh…