【C++】STL——unordered_map和unordered_set的介绍和使用

news2024/10/5 7:24:43

unordered_set和unordered_map的介绍和使用

在这里插入图片描述

文章目录

  • unordered_set和unordered_map的介绍和使用
  • 一、unordered系列关联式容器
  • 二、unordered_set
    • 1.unordered_set的介绍
    • 2.unordered_set的构造方式
    • 3.unordered_set的函数接口说明
    • 4.unordered_multiset的介绍及使用
  • 三、unordered_map
    • 1.unordered_map的介绍
    • 2.unordered_map的构造方式
    • 3.unordered_map的函数接口说明
    • 4.unordered_multimap的介绍及使用
  • 四、map/set与unordered_map/unordered_set的区别
  • 五、set/unordered_set的性能对比

一、unordered系列关联式容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到O(logN) ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。下面就开始依次进行讲解。


二、unordered_set

1.unordered_set的介绍

  • 1、unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。
  • 2、在unordered_set中,元素的值同时也是唯一地标识它的key
  • 3、在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。
  • 4、unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低
  • 5、它的迭代器至少是前向迭代器。(单向迭代器)

2.unordered_set的构造方式

  • 1、构造一个空容器
unordered_set<int> s1;
  • 2、拷贝构造一个容器
unordered_set<int> s2(s1);
  • 3、使用迭代器构造一段区间
string str("string");
unordered_set<string> s3(str.begin(), str.end());

3.unordered_set的函数接口说明

成员函数功能说明
begin获取容器中第一个元素的正向迭代器
end获取容器中最后一个元素下一个位置的正向迭代器
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数

示例:

void test_unordered_set2()
{
	unordered_set<int> us;
	//插入元素(去重)
	us.insert(1);
	us.insert(12);
	us.insert(6);
	us.insert(23);
	us.insert(3);
	us.insert(6);
	us.insert(0);
	//遍历容器方式一(范围for)
	for (auto e : us)
	{
		cout << e << " "; // 1 12 6 23 3 0
	}
	cout << endl; 
	//删除元素方式一
	us.erase(3);
	//删除元素方式二
	unordered_set<int>::iterator pos = us.find(1); //查找值为1的元素
	if (pos != us.end())
	{
		us.erase(pos);
	}
	//遍历容器方式二(迭代器遍历)
	unordered_set<int>::iterator it = us.begin();
	while (it != us.end())
	{
		cout << *it << " "; // 12 6 23 0
		it++;
	}
	cout << endl; 
	//容器中值为2的元素个数
	cout << us.count(2) << endl; //0
	//容器大小
	cout << us.size() << endl; //4
	//清空容器
	us.clear();
	//容器判空
	cout << us.empty() << endl; //1
	//交换两个容器的数据
	unordered_set<int> tmp{1, 2, 3, 4,};
	us.swap(tmp);
	for (auto e : us)
	{
		cout << e << " ";//1 2 3 4
	}
	cout << endl; 
}

4.unordered_multiset的介绍及使用

unordered_multiset和unordered_set的底层都是用哈希表来实现的,所提供的成员函数和unordered_set无显著差异,唯一的区别在于unordered_multiset允许键值冗余,即key值可以是一样的,但是unordered_set不允许。对比如下:

image-20230412004509679

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

成员函数count功能说明
unordered_set对象值为key的元素存在则返回1,不存在则返回0
unordered_multiset对象返回键值为key的元素的个数
成员函数ind功能说明
unordered_set对象返回值为key的元素的迭代器位置
unordered_multiset对象返回底层哈希表中的第一个值为key的元素的迭代器

三、unordered_map

1.unordered_map的介绍

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

2.unordered_map的构造方式

  • 1、构造一个空容器:
unordered_map<string, int> mp1;
  • 2、拷贝构造一个容器:
unordered_map<string, int> mp2(mp1);
  • 3、使用迭代器区间构造一个容器:
unordered_map<string, int> mp2(mp1.begin(), mp1.end());

3.unordered_map的函数接口说明

  • 1、unordered_map的容量
函数声明功能介绍
bool empty() const检测是否为空
size_t size() const获取有效元素个数
  • 2、unordered_map的迭代器
函数声明功能介绍
begin赶回unordered_map第一个元素的迭代器位置
end返回unordered_map最后一个元素下一个位置的迭代器
cbegin返回unordered_map第一个元素的const迭代器
cend返回unordered_map最后一个元素下一个位置的const迭代器
  • 3、unordered_map的元素访问
函数声明功能介绍
operator[ ]返回与key对应的value,没有一个默认值

**注意:**针对于[ ]的重载,该函数实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶中插入,针对插入成功与否,有如下说明:

  1. 如果key不在哈希桶中,插入成功,返回V()
  2. 若key已经在哈希桶中,插入失败,将key对应的value返回

其实和map的[ ]运算符重载的规则没有啥区别。

  • 4、unordered_map的查询
函数声明功能介绍
iterator find(const K& key)返回key在哈希桶中的位置
size_t count(const K& key)返回哈希桶中关键码为key的键值对的个数

**注意:**unordered_map中key是不能重复的,因此count函数的返回值最大为1。

  • 5、unordered_map的修改操作
函数声明功能介绍
insert向容器中插入键值对
erase删除容器中的键值对
void clear清空容器中的有效元素个数
void swap(unordered map&)交换两个容器中的元素
  • 6、unordered_map的桶操作
函数声明功能介绍
size_t bucket_count() const返回哈希桶中桶的总个数
size_t bucket_size(size_t n) const返回n号桶中有效元素的总个数
size_t bucket(const K& key)返回元素key所在的桶号

示例:

void test_unordered_map3()
{
	unordered_map<string, string> mp;
	/*insert插入*/
	//1:借助pair构造函数
	pair<string, string> kv("string", "字符串");
	mp.insert(kv);
	//2:借助pair构造匿名对象插入
	mp.insert(pair<string, string>("blue", "蓝色"));
	//3:调用make_pair函数模板插入
	mp.insert(make_pair("sky", "天空"));
	//4:使用[]运算符重载函数进行插入
	mp["快乐"] = "happy";
	//5:使用{}
	mp.insert({ "左边", "left"});
	/*遍历*/
	//1:迭代器遍历
	unordered_map<string, string>::iterator it = mp.begin();
	while (it != mp.end())
	{
		cout << it->first << ":" << it->second << " ";
		it++;
	}
	cout << endl; // string:字符串 blue:蓝色 sky:天空 happy:快乐 left:左边
	//2:范围for
	for (auto e : mp)
	{
		cout << e.first << ":" << e.second << " ";
	}	
	cout << endl; // string:字符串 blue:蓝色 sky:天空 happy:快乐 left:左边
	/*删除*/
	//1:根据key删除
	mp.erase("string");
	//2:根据迭代器位置删除
	unordered_map<string, string>::iterator pos = mp.find("sky");
	if (pos != mp.end())
	{
		mp.erase(pos);
	}
	for (auto e : mp)
	{
		cout << e.first << ":" << e.second << " ";
	}
	cout << endl; // blue:蓝色 happy:快乐 左边:left
	/*修改*/
	//1:通过迭代器位置修改
	pos = mp.find("快乐");
	if (pos != mp.end())
	{
		pos->second = "ikun";
	}
	//2:通过[]修改
	mp["左边"] = "小黑子";
	for (auto e : mp)
	{
		cout << e.first << ":" << e.second << " ";
	}
	cout << endl; // blue:蓝色 快乐:ikun 左边:小黑子
	/*交换*/
	unordered_map<string, string> tmp{ { "2023", "年"}, {"4", "月"}, {"3", "日"}};
	mp.swap(tmp);
	for (auto e : mp)
	{
		cout << e.first << e.second << " ";
	}
	cout << endl; //2023年4月3日
}

4.unordered_multimap的介绍及使用

unordered_multimap和unordered_map的底层都是用哈希表来实现的,所提供的成员函数和unordered_map无显著差异,唯一的区别在于unordered_multimap允许键值冗余,即key值可以是一样的,但是unordered_map不允许。对比如下:

image-20230412010827097

unordered_multimap允许键值冗余,这也就导致其内部的find和count函数和unordered_map中的有所区别,如下:

成员函数count功能说明
unordered_map对象值为key的元素存在则返回1,不存在则返回0
unordered_multimap对象返回键值为key的元素的个数
成员函数find功能说明
unordered_map对象返回值为key的元素的迭代器位置
unordered_multimap对象返回底层哈希表中的第一个值为key的元素的迭代器

四、map/set与unordered_map/unordered_set的区别

下面将从如下几个角度进行对比:

unordered_map / unordered_setmap / set
底层数据结构哈希表/散列表红黑树
是否有序无序有序
查找的效率O(1)O(logN)
迭代器类型单向迭代器双向迭代器
头文件#include<unordered_map>
#include<unordered_set>
#include < map >
#include < set >

五、set/unordered_set的性能对比

因map与unordered_map容器的差别和set与unordered_set容器的差别类似,所以下面我们就以set和unordered_set测试为例,来测试插入、删除、查找的效率

void test_speed()
{
	const size_t N = 1000000;

	unordered_set<int> us;
	set<int> s;

	vector<int> v;
	v.reserve(N);
	srand((unsigned int)time(0));
	for (size_t i = 0; i < N; ++i)
	{
		//v.push_back(rand());
		//v.push_back(rand()+i);
		v.push_back(i);
	}

	size_t begin1 = clock();
	for (auto e : v)
	{
		s.insert(e);
	}
	size_t end1 = clock();
	cout << "set insert:" << end1 - begin1 << endl;

	size_t begin2 = clock();
	for (auto e : v)
	{
		us.insert(e);
	}
	size_t end2 = clock();
	cout << "unordered_set insert:" << end2 - begin2 << endl;


	size_t begin3 = clock();
	for (auto e : v)
	{
		s.find(e);
	}
	size_t end3 = clock();
	cout << "set find:" << end3 - begin3 << endl;

	size_t begin4 = clock();
	for (auto e : v)
	{
		us.find(e);
	}
	size_t end4 = clock();
	cout << "unordered_set find:" << end4 - begin4 << endl;

	cout << s.size() << endl;
	cout << us.size() << endl;

	size_t begin5 = clock();
	for (auto e : v)
	{
		s.erase(e);
	}
	size_t end5 = clock();
	cout << "set erase:" << end5 - begin5 << endl;

	size_t begin6 = clock();
	for (auto e : v)
	{
		us.erase(e);
	}
	size_t end6 = clock();
	cout << "unordered_set erase:" << end6 - begin6 << endl;

}

image-20230407233602006

总结:当测试数据量较少时,二者差距不大,数据量较大时,用unordered_系列更优。

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

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

相关文章

【建议收藏】数据库 SQL 入门——约束(内附演示)

文章目录&#x1f4da;引言&#x1f4d6;约束&#x1f4d1;非空约束&#x1f4d1;唯一约束&#x1f4d1;主键约束&#x1f4d1;默认约束&#x1f4d1;检查约束&#x1f4d1;外键约束&#x1f516;外键的添加&#x1f516;删除/更新外键&#x1f4cd;总结&#x1f4da;引言 &…

【高危】Apache Linkis Gateway模块存在身份验证绕过漏洞(CVE-2023-27987)

漏洞描述 Apache Linkis 是一个用于将上层应用与底层数据引擎解耦&#xff0c;提供标准化接口的中间件。Gateway 是 Linkis 接受客户端和外部请求的主要入口点&#xff0c; 在 Apache Linkis 受影响版本中&#xff0c;由于在 Linkis Gateway 部署时产生的Token默认为LINKIS_C…

Linux打印口/LPT口出厂测试工具与使用说明

1 软件功能 该软件用于在Linux平台测试CH35X/CH38X&#xff08;PCI/PCIe转串并口&#xff09;的并口各引脚功能是否正常。方便对设备进行出厂测试。 2 并口测试硬件治具 在测试前&#xff0c;需要制作单独的硬件治具&#xff0c;按下表连接信号线&#xff1a; 25针并口座子堵…

面向削峰填谷的电动汽车多目标优化调度策略

说明书 MATLAB代码&#xff1a;面向削峰填谷的电动汽车多目标优化调度策略 关键词&#xff1a;电动汽车 削峰填谷 多目标 充放电优化 参考文档&#xff1a;店主自己整理的说明文档&#xff0c;公式、约束、数据齐全&#xff0c;可联系我查看 仿真平台&#xff1a;MATLAB YA…

iPhone如何不用iTunes将视频传输到电脑上?

随着智能手机的普及&#xff0c;iPhone已经成为了人们生活中必不可少的一部分。而随着iPhone摄像功能的逐渐完善&#xff0c;越来越多的用户开始将iPhone作为拍摄视频的工具。 但是&#xff0c;将iPhone中的视频传输到电脑并进行后续编辑处理或者备份储存&#xff0c;对于许多…

二极管专题:二极管钳位电路

二极管钳位电路 之前我们说过二极管的限幅功能 二极管专题&#xff1a;限幅电路。今天说的二极管的钳位电路和二极管的限幅电路都是利用了二极管正向压降一定的这么一个特点。限幅电路和钳位电路你说区别大呢&#xff0c;它也不大&#xff0c;说小呢也不小。就看你怎么理解了&…

Linux proc文件系统介绍

Linux proc文件系统 /proc/cmdline Arguments passed to the Linux kernel at boot time. Often done via a boot manager such as lilo(8) or grub(8) proc/[pid]/coredump_filter Since kernel 2.6.23, the Linux-specific /proc/PID/coredump_filter file can be used …

大数据项目实战之数据仓库:电商数据仓库系统——第6章 数据仓库环境准备

第6章 数据仓库环境准备 6.1 数据仓库运行环境 6.1.1 Hive环境搭建 1&#xff09;Hive引擎简介 Hive引擎包括&#xff1a;默认MR、Tez、Spark。 Hive on Spark&#xff1a;Hive既作为存储元数据又负责SQL的解析优化&#xff0c;语法是HQL语法&#xff0c;执行引擎变成了Sp…

【收藏】2023欧洲 KubeCon 和云原生大会上关于WebAssembly的一切

KubeCon CloudNativeCon EU 2023将于4月18日至21日在阿姆斯特丹举行&#xff0c;对于云原生开发者和云原生用户是一年中无比期待的大会。会议为期四天&#xff0c;是保持云原生计算最新趋势&#xff0c;与同行建立联系&#xff0c;并从行业专家学习的绝佳机会。此外&#xff0…

2023年税务师事务所行业研究报告

第一章 行业发展概况 1.1 行业概况 税务师事务所是依法设立并承办法律、法规、规章规定的涉税服务和鉴证业务的社会中介机构。税务师事务所的组织形式为有限责任制税务师事务所和合伙制税务师事务所&#xff0c;以及国家税务总局规定的其他形式。税务师事务所应当依法纳税&am…

软件测试实验:静态测试

目录 前言 一、实验目的 二、实验内容 三、实验步骤 四、实验过程 1、学生宿舍管理系统代码 2、汇总表 3、C语言编码规范 总结 前言 软件测试是软件开发过程中不可或缺的一个环节&#xff0c;它可以保证软件的质量和功能&#xff0c;提高用户的满意度和信任度。软件测…

通信工程有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是通信工程领域的一些SCI期刊推荐&#xff1a; IEEE Transactions on Communications&#xff1a; 该期刊由IEEE出版&#xff0c;是通信工程领域的顶级期刊&#xff0c;涵盖了通信系统、信号处理、无线通信、光通信、网络通信、通信安全等方面的研究。 IEEE Journal on S…

如何使用公网远程访问jupyter notebook【cpolar内网穿透】

文章目录前言视频教程1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口5. 固定公网地址转载自远控源码文章&#xff1a;公网远程访问jupyter notebook【cpolar内网穿透】 前言 Jupyter Notebook&#…

【Redis】多级缓存

【Redis】多级缓存 文章目录【Redis】多级缓存1. 传统缓存的问题2. 多级缓存方案2.1 JVM进程缓存2.1.1 本地进程缓存2.1.2 Caffeine2.2 Nginx缓存2.2.1 准备工作2.2.21. 传统缓存的问题 传统的缓存策略一般是请求到达 tomcat 后&#xff0c;先查询redis&#xff0c;如果未命中…

微服务高级篇【3】之分布式缓存Redis集群

文章目录前言一 单机Redis存在的问题二 Redis的安装三 Redis持久化3.1 RDB持久化3.1.1 触发条件3.1.2 RDB原理3.1.3 小结3.2 AOF持久化3.2.1 AOF原理3.2.2 AOF配置3.2.3 AOF文件重写3.3 RDB与AOF对比四 Redis主从集群4.1 搭建主从架构4.2 搭建主从集群4.2.1 集群结构4.2.2 准备…

【FFmpeg】自定义编码器适配

目录1 编码流程1.1 整体流程1.2 内部流程2 适配接口2.1 init、close2.2 option2.3 receive2.4 encode2.5 零拷贝的设计1 编码流程 FFmpeg是一个开源的多媒体框架&#xff0c;底层可对接实现多种编解码器&#xff0c;下面参考文件doc/examples/encode_video.c分析编码一帧的流程…

Adobe Illustrator2023(AI2023)图文安装教程

Adobe Illustrator2023(AI2023)简称AI&#xff0c;是一种应用于出版、多媒体和在线图像的工业标准矢量插画的软件。该软件主要应用于印刷出版、海报书籍排版、专业插画、多媒体图像处理和互联网页面的制作等&#xff0c;也可以为线稿提供较高的精度和控制&#xff0c;适合生产任…

【Camunda】 -- Docker 安裝及使用

【Camunda】 -- Docker 安裝及使用1. Docker install Camunda platform1.1 Web2. Big Data -- Postgres1.1 Big Data -- Postgres3.Awakening1.1 Big Data -- PostgresCamunda platform 是一個任務監控的平台。 Camunda Modeler是建模工具。 1. Docker install Camunda platfor…

【超详细教程】解决libxxx.so: cannot open shared object file: No file or directory

一、参考资料 error while loading shared libraries的解决方案 libascend_hal.so: cannot open shared object file:No such…解决办法-云社区-华为云 (huaweicloud.com) 二、相关介绍 1. -lxxx.so命名 lxxx means lib lib-name .solc means libc.so, lltdl means lib…

C++学习从基础到高阶(基于黑马程序员教程)

视频链接&#xff1a;黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难&#xff08;52个小时&#xff09; C语言中文网&#xff1a;http://c.biancheng.net/cplus/ Visual Studio 2022 下载地址&#xff1a;https://visualstudio.microsoft.com/zh-hans/downloads/ Visu…