C++STL剖析(九)—— unordered_map和unordered_multimap的概念和使用

news2024/11/28 2:39:35

文章目录

  • 1. unordered_map的介绍和使用
    • 🍑 unordered_map的构造
    • 🍑 unordered_map的使用
      • 🍅 insert
      • 🍅 operator[ ]
      • 🍅 find
      • 🍅 erase
      • 🍅 size
      • 🍅 empty
      • 🍅 clear
      • 🍅 swap
      • 🍅 count
  • 2. unordered_multimap的介绍和使用
    • 🍑 unordered_multimap的使用
      • 🍅 find
      • 🍅 count


1. unordered_map的介绍和使用

unordered_map 的介绍:

  • unordered_map 是存储 <key, value> 键值对的关联式容器,其允许通过keys快速的索引到与其对应的 value。
  • 在 unordered_map 中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
  • 在内部,unordered_map 没有对 <kye, value> 按照任何特定的顺序排序,为了能在常数范围内找到 key 所对应的 value,unordered_map 将相同哈希值的键值对放在相同的桶中。
  • unordered_map 容器通过 key 访问单个元素要比 map 快,但它通常在遍历元素子集的范围迭代方面效率较低。
  • unordered_map 实现了直接访问操作符(operator[]),它允许使用 key 作为参数直接访问 value。
  • 它的迭代器至少是前向迭代器。

🍑 unordered_map的构造

构造一个 unordered_map 容器对象,根据使用的构造函数版本初始化其内容,我们主要掌握 3 种方式即可:

在这里插入图片描述

(1)构造一个某个类型的空容器

unordered_map<string, int> um1; // 构造一个key为string类型,value为int类型的空容器

(2)拷贝构造某类型容器

unordered_map<string, int> um1({ {"apple", 1}, {"lemon", 2}});
unordered_map<string, int> um2(um1); // 拷贝构造同类型容器um1的复制品

(3)使用迭代器区间进行初始化构造

构造一个 unordered_map 对象,其中包含范围 [first,last) 中每个元素的副本。

unordered_map<string, int> um1({ {"apple", 1}, {"lemon", 2}});
unordered_map<string, int> um3(um1.begin(), um1.end()); // 使用迭代器拷贝构造um1容器某段区间的复制品

🍑 unordered_map的使用

unordered_map 的成员函数主要分为:迭代器,容量操作,修改操作。

在这里插入图片描述

我这里只列举几个常用的,其它的可以看 文档 学习。

🍅 insert

在 unordered_map 中插入新元素。

只有当每个元素的键不等同于容器中已经存在的任何其他元素的键时,才会插入它,也就是说 unordered_map 中的键是唯一的。

在这里插入图片描述

(1)构造匿名对象插入

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });

	// 构造匿名对象插入新元素
	um.insert(pair<string, double>("milk", 2.0));
	um.insert(pair<string, double>("eggs", 6.5));
	um.insert(pair<string, double>("sugar", 0.8));

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

(2)调用 make_pair 函数模板插入

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });

	// 调用make_pair函数模板插入新元素
	um.insert(make_pair("milk", 2.0));
	um.insert(make_pair("eggs", 6.5));
	um.insert(make_pair("sugar", 0.8));

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

(3)初始化列表插入

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um({ {"apple", 1.0}, {"lemon", 2.0} });

	// 初始化列表插入新元素
	um.insert({ "sugar", 0.8 });
	um.insert({ "eggs", 6.5 });
	um.insert({ "salt", 0.1 } );

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

🍅 operator[ ]

如果 k 与容器中元素的键匹配,则函数返回对其映射值的引用。

如果 k 与容器中任何元素的键不匹配,该函数将插入一个具有该键的新元素,并返回对其映射值的引用。

注意:这总是将容器大小增加 1,即使没有为元素分配映射值(使用默认构造函数构造元素)。

在这里插入图片描述

(1)利用 [] 运算符重载函数进行插入

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um;

	// 利用[]运算符重载函数进行插入
	um["apple"] = 1.5;
	um["lemon"] = 2.0;
	um["sugar"] = 0.8;

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

(2)利用 [] 运算符重载函数进行修改

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um;

	// 利用[]运算符重载函数进行插入
	um["apple"] = 1.5;
	um["lemon"] = 2.0;
	um["sugar"] = 0.8;

	// 利用[]运算符重载函数修改value
	um["apple"] = 8.88;

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

总结:

  • 若当前容器中已有键值为 key 的键值对,则返回该键值对 value 的引用。
  • 若当前容器中没有键值为 key 的键值对,则先插入键值对 <key, value()>,然后再返回该键值对中 value 的引用。

🍅 find

在容器中搜索以 k 为键的元素,如果找到它,就返回一个迭代器,否则就返回 unordered_map::end(容器末端之前的元素)的迭代器。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um;

	// 利用[]运算符重载函数进行插入
	um["mom"] = 5.4;
	um["dad"] = 6.1;
	um["bro"] = 5.9;

	// 查找"dad"
	auto pos = um.find("dad");

	if (pos != um.end())
	{
		cout << pos->first << " is " << pos->second;
	}
	else
	{
		cout << "not found" << endl;
	}
}

运行结果

在这里插入图片描述

🍅 erase

从 unordered_map 容器中移除单个元素或一组元素([first,last))。

通过调用每个元素的析构函数,这有效地减少了容器的大小。

在这里插入图片描述

(1)从容器中删除单个元素(直接传要删除的元素)

void test_unordered()
{
	// 构造对象
	unordered_map<string, string> um;

	// 填充容器
	um["U.S."] = "Washington";
	um["U.K."] = "London";
	um["France"] = "Paris";
	um["Russia"] = "Moscow";
	um["China"] = "Beijing";
	um["Germany"] = "Berlin";
	um["Japan"] = "Tokyo";

	// 直接删除"Japan"
	um.erase("Japan");

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
	
}

运行结果

在这里插入图片描述

(2)从容器中删除单个元素(搭配 find 使用)

void test_unordered()
{
	// 构造对象
	unordered_map<string, string> um;

	// 填充容器
	um["U.S."] = "Washington";
	um["U.K."] = "London";
	um["France"] = "Paris";
	um["Russia"] = "Moscow";
	um["China"] = "Beijing";
	um["Germany"] = "Berlin";
	um["Japan"] = "Tokyo";

	// 查找"Russia"的位置
	auto pos = um.find("Russia");

	if (pos != um.end())
	{
		um.erase(pos);
		cout << "delete success" << endl;
	}
	else
	{
		cout << "not found" << endl;
	}
}

运行结果

在这里插入图片描述

(3)从容器中删除一组元素(搭配 find 使用)

void test_unordered()
{
	// 构造对象
	unordered_map<string, string> um;

	// 填充容器
	um["U.S."] = "Washington";
	um["U.K."] = "London";
	um["France"] = "Paris";
	um["Russia"] = "Moscow";
	um["China"] = "Beijing";
	um["Germany"] = "Berlin";
	um["Japan"] = "Tokyo";

	// 查找"France"的位置
	auto pos = um.find("France");

	// 删除从"France"开始后面所有的元素
	um.erase(pos, um.end());

	// 遍历
	for (auto e : um)
	{
		cout << e.first << ": " << e.second << endl;
	}
}

运行结果

在这里插入图片描述

🍅 size

返回 unordered_map 容器中的元素数量。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 构造对象
	unordered_map<string, double> um = { 
		{"milk", 2.30}, 
		{"potatoes", 1.90}, 
		{"eggs", 0.40} 
	};

	cout << "size: " << um.size() << endl;

	// 插入重复元素
	um["milk"] = 5.80;
	cout << "size: " << um.size() << endl;
}

运行结果

在这里插入图片描述

🍅 empty

返回一个 bool 值,指示 unordered_map 容器是否为空,即其大小是否为 0。

这个函数不会以任何方式修改容器的内容。

在这里插入图片描述

代码示例

void test_unordered()
{
	unordered_map<int, int> um1; // 构造空容器
	unordered_map<int, int> um2 = { {1,10},{2,20},{3,30} }; // 构造非空容器

	// um1是空容器,所以结果为真
	cout << "um1 " << (um1.empty() ? "is empty" : "is not empty") << endl;

	// um2不是空容器,所以结果为假
	cout << "um2 " << (um2.empty() ? "is empty" : "is not empty") << endl;
}

运行结果

在这里插入图片描述

🍅 clear

unordered_map 容器中的所有元素都将被删除,会去调用它们的析构函数,并将它们从容器中移除,使容器的大小为 0。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化容器
	unordered_map<string, string> um1 = {
		{"house","maison"},
		{"car","voiture"},
		{"grapefruit","pamplemousse"}
	};

	// 清空容器
	um1.clear();

	// 重新插入数据
	um1["hello"] = "bonjour";
	um1["sun"] = "soleil";

	// 遍历
	for (auto& x : um1)
	{
		cout << x.first << "=" << x.second << endl;
	}
}

运行结果

在这里插入图片描述

🍅 swap

通过 ump 的内容交换容器的内容,ump 是另一个包含相同类型元素的 unordered_map 对象,大小可能不同。

这个函数在容器之间交换指向数据的内部指针,而不实际对单个元素执行任何复制或移动,允许常量时间执行,无论大小如何。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化um1和um2容器
	unordered_map<string, string>
		um1 = { {"Star Wars","G"},{"Alien","R"} },
		um2 = { {"Inception","C"},{"Donnie Darko","R"} };

	// 交换两个容器的内容
	um1.swap(um2);

	// 遍历um1
	cout << "um1: ";
	for (auto& x : um1)
	{
		cout << x.first << "-" << x.second << ", ";
	}
	cout << endl;

	// 遍历um2
	cout << "um2: ";
	for (auto& x : um2)
	{
		cout << x.first << "-" << x.second << ", ";
	}
}

运行结果

在这里插入图片描述

🍅 count

在容器中搜索键为 k 的元素,并返回找到的元素数。

因为 unordered_map 容器不允许重复键,这意味着如果容器中存在具有该键的元素,则函数实际返回 1,否则返回 0。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化容器
	unordered_map<string, double> um = { 
		{"Burger",2.99}, 
		{"Fries",1.99}, 
		{"Soda",1.50} 
	};

	// 在um中查找下列的数据
	for (auto& x : { "Burger","Pizza","Salad","Soda" }) 
	{
		if (um.count(x) > 0)
			std::cout << "um has " << x << std::endl;
		else
			std::cout << "um has no " << x << std::endl;
	}
}

运行结果

在这里插入图片描述

2. unordered_multimap的介绍和使用

unordered_multimap 的介绍:

  • multimap 是一种关联容器,它存储由键值和映射值组合而成的元素,很像 unordered_map 容器,但是允许不同的元素具有等价的键。
  • 在 unordered_multimap 中,键值通常用于唯一标识元素,而映射值是一个对象,其内容与该键相关联。键和映射值的类型可能不同。
  • 在内部,unordered_multimap 中的元素不会根据它们的键值或映射值以任何特定的顺序进行排序,而是根据它们的散列值将它们组织到 bucket中,以允许直接通过键值快速访问单个元素(平均时间复杂度恒定)。
  • 具有等效键的元素被分组在同一个 bucket 中,并且迭代器可以遍历所有这些元素。
  • 容器中的迭代器至少是前向迭代器。

注意,这个容器不是在它自己的头文件中定义的,而是与 unordered_map 共享头文件 <unordered_map>

🍑 unordered_multimap的使用

unordered_multimap 容器与 unordered_map 容器的底层数据结构是一样的,都是哈希表。

其次,它们所提供的成员函数的接口都是基本一致的,这两种容器唯一的区别就是,unordered_multimap 容器允许键值冗余,即 unordered_multimap 容器当中存储的键值对的 key 值是可以重复的。

其次,由于 unordered_multimap 容器允许键值对的键值冗余,调用 [] 运算符重载函数时,应该返回键值为 key 的哪一个键值对的 value 的引用存在歧义,因此在 unordered_multimap 容器当中没有实现 [] 运算符重载函数。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化容器
	unordered_multimap<int, string> umm;

	// 插入键值对,允许重复
	umm.insert(make_pair(2023, "跑步"));
	umm.insert({ 2023, "打球" });
	umm.insert({ 2023,"玩游戏" });

	// 遍历umm
	for (auto x : umm)
	{
		cout << x.first << ": " << x.second << endl;
	}
}

可以看到,key 是可以重复的。

在这里插入图片描述

另外,它和 unordered_map 容器所提供的成员函数的接口都是基本一致的,所以就不全部列举了,只列举几个稍微有点小差别的函数接口。

🍅 find

在容器中搜索以 key 为键的元素,如果找到,则返回该元素的迭代器,否则返回 unordered_multimap::end(超出容器末端的元素)的迭代器。

也就是返回底层哈希表中第一个找到的键值为 key 的键值对的迭代器。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化容器
	unordered_multimap<string, string> umm;

	// 插入键值对,允许重复
	umm.insert({ "mom", "妈妈" });
	umm.insert({ "mom", "母亲" });
	umm.insert({ "dad", "父亲" });
	umm.insert({ "bro", "兄弟" });

	// 查找第一个"mom"的key,并输出对应的value
	cout << "one of the values for 'mom' is: ";
	cout << umm.find("mom")->second;
}

运行结果

在这里插入图片描述

🍅 count

在容器中搜索键为 k 的元素,并返回找到的元素个数。

在这里插入图片描述

代码示例

void test_unordered()
{
	// 初始化容器
	unordered_multimap<string, string> umm = {
		{"orange","FL"},
		{"strawberry","LA"},
		{"strawberry","OK"},
		{"pumpkin","NH"} 
	};

	// 统计下面三个单词在容器中出现的次数
	for (auto& x : { "orange","lemon","strawberry" }) 
	{
		cout << x << ": " << umm.count(x) << " 次" << endl;
	}
}

运行结果

在这里插入图片描述

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

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

相关文章

程序环境和预处理详解

文章目录一、程序环境1.1 - 翻译环境1.1.1 - 编译1.1.1.1 - 预编译&#xff08;预处理&#xff09;1.1.1.2 - 编译1.1.1.3 - 汇编1.1.2 - 链接1.2 - 执行环境二、预处理详解2.1 - 预定义符号2.2 - #define2.2.1 - #define 定义标识符2.2.1.1 - 语法2.2.1.2 - 建议2.2.2 - #defi…

AI极大地改变了知识创造与分发的逻辑

AI改变了&#xff5e;知识创造、分发的逻辑 细想一下这是恐怖的 已经传导出给教育的压力 趣讲大白话&#xff1a;AI机器人成了随身专家 *********** 1.以前靠秀才创造、分发知识 2.后来是教育体系为主 3.再后&#xff0c;互联网平台聚合和分发 4.将来可能大部分是机器人创造、分…

Xshell和Xftp的下载和在linux虚拟机中的使用

Xshell和Xftp的下载和在linux虚拟机中的使用一、Xshell和Xftp简介XshellXftp二、 Xshell和Xftp下载三、Xshell和Xftp安装Xshell安装Xftp安装四、 Xshell和Xftp使用找到linux虚拟机的ip地址Xshell的使用Xftp的使用一、Xshell和Xftp简介 Xshell Xshell 是一个强大的安全终端模拟…

对灵敏度分析技术进行建模(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

9、MyBatis框架——使用注解开发实现数据库增删改查操作、一级缓存、二级缓存、MyBatis实现分页

目录 一、使用注解开发实现数据库增删改查操作 1、搭建项目 2、使用注解开发操作数据库 二、一级缓存 1、一级缓存失效的情况 三、二级缓存 1、手动开启二级缓存cacheEnabled 2、二级缓存机制 四、MyBatis实现分页 1、配置环境 2、startPage()开启分页 3、PageInfo…

charles+夜神模拟器抓包

1.资料地址: 链接&#xff1a;https://pan.baidu.com/s/1w9qYfFPJcduN4If50ICccw 提取码&#xff1a;a7xa2.安装charles 和夜神模拟器并配置参考地址: https://www.beierblog.com/archives/%E4%BA%B2%E6%B5%8B%E5%AE%8C%E5%85%A8%E5%8F%AF%E8%A1%8Ccharles%E6%8A%93%E5%8C%85%E…

两道链表经典算法题---链表有无环(基础+进阶)

生活就像一盒巧克力&#xff0c;你永远不知道你会得到什么。——《阿甘正传》目前自己粗略的学完数据结构&#xff0c;正在开始刷算法题目。个人觉得算法是一个积累&#xff0c;循序渐进的的过程&#xff0c;需要不断加量&#xff0c;进而达到所谓的质。链表作为数据结构一个重…

全网详解MyBatis-Plus LambdaQueryWrapper的使用说明以及LambdaQueryWrapper和QueryWapper的区别

文章目录1. 文章引言2. 代码演示3. 分析LambdaQueryWrapper3.1 引入LambdaQueryWrapper的原因3.2 LambdaQueryWrapper和QueryWapper的区别4. 重要总结1. 文章引言 今天在公司写代码时&#xff0c;发现同事使用LambdaQueryWrapper来查询数据&#xff0c;而我一直习惯使用QueryW…

没对比没伤害,浙江男不买包包被女友拖拽,深圳男收三个女孩红包

又是一年一度的情人节&#xff0c;虽然这只是一个西方的节日&#xff0c;却被中国的商人们充分利用&#xff0c;也造成了不小的社会矛盾。在今年的情人节里&#xff0c;浙江就发生了一件奇葩的事情&#xff0c;一位女子因不满其男友 不给自己买两万元包包&#xff0c;就在商场里…

Onvif协议如何判断摄像机支持 —— 筑梦之路

有人就问什么是Onvif协议呢&#xff1f; 全称为&#xff1a;Open Network Video Interface Forum.缩写成Onvif。 翻译过来是&#xff1a;开放型网络视频接口论坛&#xff0c;目的是确保不同安防厂商的视频产品能够具有互通性&#xff0c;这样对整体安防行业才是良性发展。 现…

【C语言编译器】01程序-编译器-IDE

目录一、程序的几个基本概念二、什么是编译器三、集成开发环境3.1 IDE简介3.2 windows 下的C语言IDE一、程序的几个基本概念 计算机程序&#xff08;Computer Program&#xff09;&#xff1b;港、台译做电脑程式。计算机程序是一组计算机能识别和执行的指令&#xff0c;运行于…

5 款最好的免费 SSD 数据恢复软件

SSD&#xff08;固态硬盘&#xff09;提供比传统硬盘更快的读/写速度&#xff0c;使启动、软件加载和游戏启动更快。因此&#xff0c;在我们选择存储设备时&#xff0c;它是一个极好的选择。但是&#xff0c;它仍然存在数据丢失的风险。假设您是受害者之一&#xff0c;正在寻找…

SpringBoot的创建和使用

SpringBoot是什么&#xff1f;SpringBoot诞生的目的就是为了简化Spring开发&#xff0c;而相对于Spring&#xff0c;SpringBoot算是一个很大的升级&#xff0c;就如同汽车手动挡变成了自动挡。Spring&#xff1a;SpringBoot&#xff1a;SpringBoot的优点SpringBoot让Spring开发…

[技术选型] ClickHouse和StarRocks的介绍

文章目录1.ClickHouse介绍2.StarRocks介绍1.ClickHouse介绍 ClickHouse是面向联机分析处理&#xff08;OLAP&#xff09;的开源分析引擎。最初由俄罗斯第一搜索引擎Yandex开发&#xff0c;于2016年开源&#xff0c;开发语言为C。由于其优良的查询性能&#xff0c;PB级的数据规…

Linux的ACL(扩展权限)规划:setfacl、getfacl

目录 什么是ACL与如何支持启动ACL ACL设置技巧&#xff1a;getfacl、setfacl getfacl命令用法 setfacl命令用法 最简单的【u&#xff1a;账号&#xff1a;权限】设置 使用默认权限设置目录未来文件的ACL权限继承 什么是ACL与如何支持启动ACL ACL是Access Control List的…

【基础篇】7 # 队列:队列在线程池等有限资源池中的应用

说明 【数据结构与算法之美】专栏学习笔记 什么是队列&#xff1f; 队列是一种操作受限的线性表数据结构&#xff0c;特点是先进先出&#xff0c;最基本的操作有&#xff1a;入队 enqueue()&#xff0c;放一个数据到队列尾部&#xff1b;出队 dequeue()&#xff0c;从队列头…

综合保税区快速发展,卖家抓紧瞄准跨境电商

综合保税区指的是我国设立在内陆地区的海关特殊监管区域&#xff0c;具有报税港区的功能&#xff0c;这是由海关参照有关规定对综合保税区进行管理&#xff0c;执行保税港区的外汇政策和税收&#xff0c;集合众多功能于一身&#xff0c;包括保税区、保税物流区、出口加工区、港…

JNI开发之-CMake方式调用第三方so

CMake方式调用第三方so背景CMake工程配置工程配置配置CMakeLists.txt配置build.gradle调用第三方so中的方法背景 最近一个项目是对接自研团队的个so库&#xff0c;因为之前都是用ndk来编译自己的so库&#xff0c;一直没有问题&#xff0c;但是用到这个自研的的so库一直有问题&…

usbmon+tcpdump+wireshark USB抓包

文章目录usbmon抓包及配合wireshark解析usbmon抓包及配合wireshark解析 usbmon首先编译为内核模块&#xff0c;然后通过modprobe usbmon加载到linux sys文件系统中 rootroot-PC:~# modprobe usbmon​ 而后 linux系统下安装 tcpdump rootroot-PC:~# apt-get install tcpdump​…

如何开发一个好用的公共组件

写在前面 当你对某一个业务场景有自己的理解&#xff0c;想提炼开发了一个很好用的组件&#xff0c;想开放给别的同学使用&#xff0c;或者甚至放在社区给任何一个人使用&#xff0c;你应该会产生以下疑问&#xff1a; 一个标准的组件是怎么样的&#xff0c;在开发过程中有哪…