【C++/STL】map和multimap的使用

上个文章我们学习了STL关联式容器 ------set 的使用,本篇文章我们将介绍另一组关联式容器map。

关于关联式容器键值对 的概念在上篇文有讲到 ->键值对。这里不再赘述

一、map的介绍

map 的底层也是基于红黑树 实现的,其内部元素根据自动升序排列。

  • map是关联式容器,它按照特定的次序存储键值对pair(key和值value组成的元素)。
  • 键值key和实值value的类型可能不同 ,在map的内部,key与value通过成员类型 value_type 绑定在一起,为其取别名称为pair。
  • 在内部,map中的元素总是按照键值key进行比较排序的。
  • map容器中元素的键值key不能被修改,但是元素的值value可以被修改

map与set相比区别如下:

存储内容上,set 存储 ,map 存储键值对( pair 类型);

元素访问上,set 仅支持访问键,map 则可通过键访问对应值,且值支持修改。

、map的使用

构造函数

主要有以下三种构造:

cpp 复制代码
// 构造一个key为string类型,value为int类型的空容器
map<string, int> m1;

// 拷贝构造key为string类型,value为int类型的m1容器的复制品
map<string, int> m2(m1); 

// 使用迭代器拷贝构造m2容器某段区间的复制品
map<string, int> m3(m2.begin(), m2.end());

insert

将对应的键值对直接插入进去(会按照搜索的规则到达相应的位置),并返回一个 pair<iterator,bool>,跟set是一样的,bool是用来判断插入成功或者失败,因为map也是不支持键值冗余的。

每个插入的键值对都是pair的匿名构造,为了提高效率,c++中提供了一个make_pair的接口

这是几种常用元素插入方式:

因为 map 中元素的键是唯一的,所以插入操作会检查被插入元素的键是否已经存在,如果存在相等的健值,则不插入该元素,并返回包含重复键的元素的迭代器(如果该重载函数有返回值)

第一个重载函数(单个元素插入)的返回值:是一个 pair

  • 插入成功时,pair 的第一个元素是指向新元素的迭代器,第二个元素是 true;
  • 当因有重复键而插入失败时,pair 的第一个元素是指向包含重复键的元素的迭代器,第二个元素是 false。

erase

下面是指定位置迭代器删除和指定元素删除

重载operator[ ]

**operator[]在map里实现的功能很强大。**可以快速实现插入或修改功能。

调用[]等同于调用这个:

cpp 复制代码
(*((this->insert(make_pair(k,mapped_type()))).first))

分布解析如下

  1. this->insert(make_pair(k, mapped_type())):
    1. this 指针指向当前对象。
    2. insert 是当前对象的一个成员函数。
    3. make_pair (k, mapped_type ()) 创建了一个键值对,其中 k 是键,mapped_type () 是默认构造的值。
    4. insert 函数将这个键值对插入到当前对象中,并返回一个 pair,其中 first 是一个迭代器,指向插入的键值对,second 是一个布尔值,表示插入是否成功。
  2. (this->insert(make_pair(k, mapped_type()))).first:
    1. 从 insert 函数返回的 pair 中取出 first,即指向插入的键值对的迭代器。
  3. *((this->insert(make_pair(k, mapped_type()))).first):
    1. 对迭代器进行解引用,得到插入的键值对。
  4. (*((this->insert(make_pair(k, mapped_type()))).first)).second:
    1. 从解引用的键值对中取出 second,即插入的值。

实际上就是这三步:

  1. 调用 insert 函数插入键值对。
  2. 拿出从 insert 函数获取到的迭代器。
  3. 返回该迭代器位置元素的值 value。

对应分解代码如下:

cpp 复制代码
mapped_type& operator[] (const key_type& k)
{
	//1、调用insert函数插入键值对
	pair<iterator, bool> ret = insert(make_pair(k, mapped_type()));
	//2、拿出从insert函数获取到的迭代器
	iterator it = ret.first;
	//3、返回该迭代器位置元素的值value
	return it->second;
}

operator[]的本质:给[]一个Key,如果存在,就返回Key对应val的引用。如果不存在,就插入Key,然后val给的是缺省值(string缺省值就是"") 。

下面是一个举例:

遍历

不能直接对迭代器解引用,因为里面有两个值。

可以范围for传引用访问。

三、multimap

multimap 容器与 map 容器的底层实现一样,都是平衡搜索树(红黑树),其次两者所提供的成员函数的接口都是基本一致的

唯一的不同点multimap 允许键值冗余,即 multimap 容器当中存储的元素是可以重复的。

multimap没有重载[],**所以只能使用insert。**multimap不能重载[],因为已经允许冗余了,如果key有多个,就不知道返回哪个key对应的val。

cpp 复制代码
void test()
{
	//是否插入看的是key,不是value
 
	//multimap支持key冗余,无论value是否一样
	multimap<int, string> mul_map;
	mul_map.insert({ 1, "Hello" });
	mul_map.insert({ 1, "Hi" });
	mul_map.insert({ 2,"Hehe" });
	mul_map.insert({ 3,"nice" });
	mul_map.insert({ 3,"nice" });
	

	cout << "multimap:" << endl;
	for (const auto& e : mul_map)
	{
		cout << e.first << " " << e.second << endl;
	}
}

由于 multimap 容器允许键值冗余,因此两个容器中成员函数 find 和 count 的意义也有所不同:

成员函数 find 功能
map 对象 返回值是键值为 key 的元素的迭代器
multimap 对象 返回底层搜索树中序的第一个键值为 key 的元素的迭代器
成员函数 count 功能
map 对象 键值为 key 的元素存在则返回 1,不存在则返回 0(find 成员函数可代替)
multimap 对象 返回键值为 key 的元素个数(find 成员函数不可代替)
相关推荐
聪明努力的积极向上3 小时前
【C#】事件简单解析
开发语言·c#
懒羊羊不懒@3 小时前
JavaSe—集合框架、Collection集合
java·开发语言
钢门狂鸭3 小时前
go开发规范指引
开发语言·驱动开发·golang
2301_795167203 小时前
玩转Rust高级应用 如何进行理解Refutability(可反驳性): 模式是否会匹配失效
开发语言·算法·rust
lllsure3 小时前
【Python】Dict(字典)
开发语言·python
云知谷4 小时前
【C/C++基本功】C/C++江湖风云录:void* 的江湖传说
c语言·开发语言·c++·软件工程·团队开发
脚踏实地的大梦想家4 小时前
【Go】P19 Go语言并发编程核心(三):从 Channel 安全到互斥锁
开发语言·安全·golang
逻极4 小时前
Rust数据类型(下):复合类型详解
开发语言·后端·rust