C++ | unordered_map与unordered_set的用法指南

news2025/1/21 9:26:24

目录

前言

一、unordered_set

1、简介

2、构造相关函数

3、容量相关函数

4、修改与查找相关接口

5、迭代器

二、unordered_map

1、简介

2、构造相关函数

3、容量相关接口

4、迭代器、查找与修改相关接口

5、方括号接口

三、红黑树系列与哈希系列对比


前言

        unordered_map与unordered_set是C++11推出的关联式容器,他们的作用与我们前面学习的map与set差不多一样,唯一不同的是这两个容器相比于map/set数据是无序的;我们从名字也可以看出来,具体上,实际上底层map/set是用的红黑树,而unordered_map/unordered_set是使用哈希来实现的;

一、unordered_set

1、简介

        unordered_set也是一种关联式容器,作用主要与我们前面学过的set相同,我们首先看这个类的声明;具体如下;

        我们可以看到这个类有四个模板参数,其中后三个都有默认的模板参数,参数一是存入Key的数据类型,与我们之前的set相同;第二个参数是哈希函数,这个以及后面的两个都可以不填,哈希函数会在后面一张写实现的时候进行介绍;

2、构造相关函数

        unordered_set的构造相关函数我们用的最多的还是如下几个;分别为无参构造、迭代器区间构造、拷贝构造;当然set也支持赋值重载;

void test_unordered_set1()
{
	// 无参默认构造
	unordered_set<int> s1;
	// 区间构造
	int arr[] = { 1,2,3,4,5,6 };
	unordered_set<int> s2(arr, arr + 5);
	// 拷贝构造
	unordered_set<int> s3(s2);

	// 赋值重载
	s2 = s1;

}

3、容量相关函数

        容量相关函数还是如下三个,这三个我们可以一看就懂了,主要还是第一个与第二个函数,第一个是查看容器是否为空,第二个是容器中储存元素个数; 

4、修改与查找相关接口

        修改相关接口主要是如下四个为主,其他的需要我们拥有右值引用相关知识,暂可不了解;查找主要以find接口为主来学习;

void test_unordered_set2()
{
	unordered_set<int> s1;
    // 插入接口
	s1.insert(2); // 返回值类型:pair<iterator,bool>
	s1.insert(5);
	s1.insert(3);
	s1.insert(1);
	s1.insert(7);
    // 删除接口
	s1.erase(3); // 返回值类型:size_type

	// 查找 find
	s1.find(5);  // 返回值是查找值的迭代器,没找到返回end()
	// 查找个数(在unordered_set中要么返回1要么返回0,因为会去重,unordered_multiset中有意义)
	cout << s1.count(3) << endl;

	// 清空s1
	s1.clear();
	// 交换
	unordered_set<int> s2;
	s1.swap(s2);
}

        关于insert的返回值是一个pair,该结构的第二个为bool值,记录是否插入成功,第一个记录插入数据迭代器的位置; 

5、迭代器

        注意,哈希版本的set与map这里都是单向迭代器,因此没有反向迭代器的概念;与set最大的不同是哈希版本是无序的;

void test_unordered_set3()
{
	unordered_set<int> s1;
	s1.insert(2); 
	s1.insert(5);
	s1.insert(3);
	s1.insert(1);
	s1.insert(7);

	// 迭代器
	unordered_set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	// 范围for
	for (auto& e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
}

        还有一些别的函数方法在我们后面模拟实现以后自然会用了,所以本文暂不介绍; 

二、unordered_map

1、简介

        同样unordered_map与map最大区别是无序性,其中map底层是红黑树,而unordered_map底层是哈希;其类声明也如下所示;最大的不同是,这里有五个模板参数,多了一个T,因为unordered_map同样也是KeyValue结构;因此多了一个T,也即是Value;

2、构造相关函数

        构造相关我们仅仅只需要会使用默认构造,范围构造,拷贝构造即可,因为大部分都是使用这三个构造;赋值我们仅仅需要会使用第一个拷贝赋值即可;其他有关右值引用知识得到后面了解;

void test_unordered_map1()
{
	// 默认构造
	unordered_map<int, int> m1;
	// 区间构造
	int arr[] = { 1,2,3,4,5,6,7 };
	unordered_map<int, int> m2;
	for (auto e : arr)
	{
		m2.insert(make_pair(e, e));
	}
	// 拷贝构造
	unordered_map<int, int> m3(m2);
	// 赋值重载
	m2 = m1;
}

3、容量相关接口

        容量相关接口非常简单,size是返回容器中元素个数,max_size是返回容器最多能存多少个元素(没啥用),empty是查看容器是否为空;

4、迭代器、查找与修改相关接口

        这里跟前面unordered_set差不多,我们就融合到一起讲解了,大体用法也差不多;没什么学习成本;

void test_unordered_map2()
{
	// 去重
	unordered_map<int, int> m1;
	// 插入接口,一般为键值对KV结构
	m1.insert(make_pair(3, 3)); // 返回值:pair<iterator,bool>
	m1.insert(make_pair(7, 7));
	m1.insert(make_pair(1, 1));
	m1.insert(make_pair(5, 5));
	m1.insert(make_pair(3, 3));

	// 查找接口
	unordered_map<int, int>::iterator it1 = m1.find(5); // 返回5位置的迭代器

	// 删除接口 返回值为 size_type (删除元素的个数)
	m1.erase(1);  // 删除key为1的键值对

	// 迭代器遍历
	unordered_map<int, int>::iterator it2 = m1.find(5);
	while (it2 != m1.end())
	{
		cout << it2->first << ": " << it2->second << endl;
		it2++;
	}
	cout << endl;
	// 范围for自然也就可以了
	for (auto& e : m1)
	{
		cout << e.first << ": " << e.second << endl;
	}
	cout << endl;

	// 交换
	unordered_map<int, int> m2;
	m1.swap(m2);
	// 清空
	m2.clear();
}

5、方括号接口

        与map一样,unordered_map也有对方括号进行重载,而且这里的方括号与map一样,功能多样化,可以插入数据,也可以修改键值对的value,还可以查找某个键值对的value;

void test_unordered_map3()
{
	unordered_map<int, int> m1;
	m1.insert(make_pair(3, 3));
	m1.insert(make_pair(7, 7));
	m1.insert(make_pair(1, 1));
	m1.insert(make_pair(5, 5));
	m1.insert(make_pair(3, 3));
	// 查找
	cout << m1[3] << endl;
	// 修改
	m1[3]++;
	// 查找
	cout << m1[3] << endl;

}

三、红黑树系列与哈希系列对比

        我们发现set/map与unordered_set/unordered_map在使用方面似乎没有什么区别,我们的红黑树系列会将数据进行排序;接下来我会从两者之间的速度进行比较;测试代码如下;

// 测试代码
void test2()
{
	const size_t N = 100000;
	unordered_set<int> us;
	set<int> s;

	vector<int> v;
	v.reserve(N);
	srand(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 << endl;

	cout << "set 插入元素个数" << s.size() << endl;
	cout << "unordered_set 插入元素个数" << us.size() << endl << 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 << endl;
}

我们分别对三种类型的数据进行比较;结果如下

        我们不难发现,综合来讲,我们的unordered系类的效率明显远远大于红黑树系列,因为我们unordered系列增删查改的综合效率为O(1);而红黑树的增删查改的综合效率为

O(log N);为什么能做到O(1),在我们探究底层原理以后我们就会有大体的认识;

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

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

相关文章

SpringCloud(待续)

单体架构特点? 简单方便&#xff0c;高度耦合&#xff0c;扩展性差&#xff0c;适合小型项目。例如:学生管理系统 分布式架构特点? 松耦合&#xff0c;扩展性好&#xff0c;但架构复杂&#xff0c;难度大。适合大型互联网项目&#xff0c;例如:京东、淘宝 微服务:一种良好的分…

vue项目环境 搭建

1、安装nodejs 2、安装vue-cli, npm i -g vue/cli-init 3、初始化项目 vue init webpack test 4、运行 cd test npm run dev

【机器学习】西瓜书习题3.5Python编程实现线性判别分析,并给出西瓜数据集 3.0α上的结果

参考代码 结合自己的理解&#xff0c;添加注释。 代码 导入相关的库 import numpy as np import pandas as pd import matplotlib from matplotlib import pyplot as plt导入数据&#xff0c;进行数据处理和特征工程 得到数据集 D { ( x i , y i ) } i 1 m , y i ∈ { 0 ,…

python+opencv学习

1. 把所有绿色通道值变为0 import cv2 import numpy as npimgcv2.imread(2.jpg) #读取图片 img[:,:,1]0 #绿色通道变为0 cv2.imshow(图片,img) #显示图片 cv2.waitKey(0) #无限地显示窗口 人生建议&#xff0c;一定要买书来学习呀&#xff0c;不是说教程不好&#xff0c;而是书…

idea application.yml配置文件没有提示或读不到配置

1.首先确定你的resources文件夹正常且yml文件图表和下面一样 不一样的右键去设置 2.确保你已经缩进了且层级关系正常 3.如果以上都不是&#xff0c;先考虑删除.idea重开试试 4.以上解决不了就装以下两个插件解决

[深入理解NAND Flash] 闪存(NAND Flash) 学习指南

依公开知识及经验整理&#xff0c;付费内容&#xff0c;禁止转载。 所在专栏 《深入理解Flash:闪存特性与实践》 1. 我想和你说 漠然回首&#xff0c;从事存储芯片行业已多年&#xff0c;这些年最宝贵的青春都献给了闪存&#xff0c;虽不说如数家珍&#xff0c;但也算专业。 …

【Git】git reflog git log

前言 日常开发过程中&#xff0c;我们经常会遇到要进行版本回退的情况&#xff0c;这时候需要使用git reflog和git reset 命令 git reflog 常用命令&#xff1a; 1、git reflog -n 查看多少条 2、git reflog show origin 查看远程历史变动 git log 什么都不加默认显示当前分…

SpringBoot项目中的web安全防护

最近这个月公司对项目进行了几次安全性扫描&#xff0c;然后扫描出来了一些安全漏洞&#xff0c;所以最近也一直在修复各种安全漏洞&#xff0c;还有就是最近在备考软考高级系统架构设计师&#xff0c;也刚好复习到了网络安全这一个章节&#xff0c;顺便将最近修复的安全漏洞总…

漏洞利用-PoC-in-GitHub+msf简单利用

查找库-PoC-in-GitHub 里面集成了几乎所有cve漏洞 下载&#xff1a;https://github.com/nomi-sec/PoC-in-GitHub 演示&#xff1a; 如想要查找vulfocus靶场中 Metabase远程命令执行漏洞 的利用方法。 可以下载一个Yomm闪电文件搜索 Yomm闪电文件搜索下载&#xff1a;https://…

Github-Copilot初体验-Pycharm插件的安装与测试

引言&#xff1a; 80%代码秒生成&#xff01;AI神器Copilot大升级 最近copilot又在众多独角兽公司的合力下&#xff0c;取得了重大升级。GitHub Copilot发布还不到两年&#xff0c; 就已经为100多万的开发者&#xff0c;编写了46%的代码&#xff0c;并提高了55%的编码速度。 …

代理模式——对象的间接访问

1、简介 1.1、概述 由于某些原因&#xff0c;客户端不想或不能直接访问某个对象&#xff0c;此时可以通过一个被称为“代理”的第三者来实现间接访问&#xff0c;该方案对应的设计模式被称为代理模式。 代理模式是一种应用很广泛的结构型设计模式&#xff0c;而且变化很多。…

活动回顾|火山引擎 DataLeap 分享:DataOps、数据治理、指标体系最佳实践(文中领取 PPT)

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 在 7 月 21 日至 22 日举行的 ArchSummit 全球架构师峰会&#xff08;深圳站&#xff09;及 DataFunCon.数据智能创新与实践大会&#xff08;北京站&#xff09;上&…

C++ 类的组合

解决复杂问题的有效方法就是将其层层分解为简单问题的组合&#xff0c;首先解决简单问题&#xff0c;复杂问题也就迎刃而解了。实际上&#xff0c;这种部件组装的生产方式广泛应用在工业生产中。例如&#xff0c;电视机的一个重要部件是显像管&#xff0c;但很多电视机厂自己并…

ARM裸机-7

1、S5PV210的地址映射 1.1、什么是地址映射 S5PV210属于ARM Cortex-A8架构&#xff0c;32位CPU&#xff0c;CPU设计时就有32根地址线&32根数据线。32根地址线决定了CPU的地址空间为4G&#xff0c;那么这4G空间如何分配使用&#xff1f;这个问题就是地址映射问题。 1.2、S…

AnimateDiff论文解读-基于Stable Diffusion文生图模型生成动画

文章目录 1. 摘要2. 引言3. 算法3.1 Preliminaries3.2. Personalized Animation3.3 Motion Modeling Module 4. 实验5.限制6. 结论 论文&#xff1a; 《AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning》 github: https://g…

高级 IO

目录 前言 什么是IO&#xff1f; 有哪些IO的的方式呢&#xff1f; 五种IO模型 这五种模型在特性有什么差别呢&#xff1f; 其他高级IO 非阻塞IO fcntl 实现函数SetNonBlock I/O多路转接之select 初识select select函数 参数说明&#xff1a; 关于timeval结构 函数…

【解惑笔记】树莓派+OpenCV+YOLOv5目标检测(Pytorch框架)

【学习资料】 子豪兄的零基础树莓派教程https://github.com/TommyZihao/ZihaoTutorialOfRaspberryPi/blob/master/%E7%AC%AC2%E8%AE%B2%EF%BC%9A%E6%A0%91%E8%8E%93%E6%B4%BE%E6%96%B0%E6%89%8B%E6%97%A0%E7%97%9B%E5%BC%80%E6%9C%BA%E6%8C%87%E5%8D%97.md#%E7%83%A7%E5%BD%95…

【多线程中的线程安全问题】线程互斥

1 &#x1f351;线程间的互斥相关背景概念&#x1f351; 先来看看一些基本概念&#xff1a; 1️⃣临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源。2️⃣临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区。3️⃣互斥&…

python与深度学习(十一):CNN和猫狗大战

目录 1. 说明2. 猫狗大战2.1 导入相关库2.2 建立模型2.3 模型编译2.4 数据生成器2.5 模型训练2.6 模型保存2.7 模型训练结果的可视化 3. 猫狗大战的CNN模型可视化结果图4. 完整代码5. 猫狗大战的迁移学习 1. 说明 本篇文章是CNN的另外一个例子&#xff0c;猫狗大战&#xff0c…