C++必修:unordered_set/unordered_map

news2024/9/21 18:32:02

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C++学习
贝蒂的主页:Betty’s blog

1. unordered_set的介绍

unordered_set是一种关联式容器,它具有以下几个特点:

  1. 基本概念
  • unordered_set是一种关联式容器,不按特定顺序存储键值。
  • 元素的值同时也是唯一标识它的key
  1. 内部存储方式
  • 内部元素没有按照特定顺序排序。
  • 为快速找到指定key,将相同哈希值的键值放在相同的桶中(开散列)。
  1. 性能特点
  • 通过key访问单个元素比set快。
  • 在遍历元素子集的范围迭代方面效率较低,因为数据并不在某个范围,而是无序的。
  1. 迭代器类型
  • 迭代器至少是前向迭代器。

具体可参考官方文档——unordered_set

2. unordered_set的功能

首先unordered_setSTL其他大多数容器一样,为了支持所有类型,所以是一个类模版。

2.1 unordered_set的初始化

unordered_set初始化会调用构造函数,其构造函数分别重载了以下几种方式:
image.png

void Test1()
{
	//1.默认无参构造
	unordered_set<int> s1;
	//2.迭代器区间初始化
	string str("betty");
	unordered_set<char> s2(str.begin(), str.end());
	//3.拷贝构造
	unordered_set<int> s3(s1);
}

2.2 unordered_set的迭代器

成员函数功能
begin获取容器中第一个元素的迭代器
end获取容器中最后一个元素下一个位置的正向迭代器

一般而言unordered_set并不支持反向迭代器,其次这些函数与其他容器的迭代器成员函数无论是功能还是用法都是一模一样的,所以上手可谓十分简单。

void Test2()
{
	vector<int> arr = { 1,2,3,4,5,6,7 };
	//迭代器区间初始化
	unordered_set<int> s1(arr.begin(), arr.end());
	//正向迭代器
	unordered_set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

image.png

2.3 unordered_set的常见成员函数

以下是unordered_set常见的成员函数:

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数
void Test3()
{
	unordered_set<int> s1;
	//插入元素并去重
	s1.insert(1);
	s1.insert(2);
	s1.insert(2);
	s1.insert(3);
	s1.insert(3);
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl; 
	unordered_set<int>::iterator it = s1.find(1);
	//如果找不到返回end()
	if (it != s1.end())
	{
		s1.erase(1);
	}
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	//容器中值为2的元素个数
	cout <<"容器中值为2的元素个数"<< s1.count(2) << endl;
}

image.png

void Test4()
{
	unordered_set<int> s1;
	s1.insert(1);
	s1.insert(2);
	s1.insert(3);
	//容器大小
	cout << s1.size() << endl;
	//清空容器
	s1.clear();
	//容器判空
	cout << s1.empty() << endl;
	vector<int> arr = { 1,2,3,4,5,6,7 };
	//迭代器区间初始化
	unordered_set<int> tmp(arr.begin(), arr.end());
	//交换两个容器的数据
	s1.swap(tmp);
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
}

image.png
值得注意的是:unordered_set的插入与删除操作可能存在迭代器失效的问题。

3. unordered_multiset

unordered_multiset的使用方式与unordered_set基本一致,唯一的区别就在于unordered_multiset允许键值冗余,即可存储重复元素。

void Test5()
{
	unordered_multiset<int> s1;
	//支持键值冗余
	s1.insert(1);
	s1.insert(1);
	s1.insert(2);
	s1.insert(2);
	s1.insert(3);
	s1.insert(4);
	unordered_multiset<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
}

image.png
值得注意的是:unordered_multisetfind返回返回底层哈希表中第一个找到的键值为val的元素的迭代器

4. unordered_map的介绍

unordered_map 是 C++ 中的关联式容器,具有以下特性:

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

具体可参考官方文档——unordered_map

5. unordered_map 的功能

首先unordered_map 同样与STL其他大多数容器一样,为了支持所有类型,所以是一个类模版。

5.1 unordered_map的初始化

unordered_map初始化会调用构造函数,其构造函数分别重载了以下几种方式:
image.png

void Test6()
{
	//1.默认无参构造
	unordered_map<int, int> m1;
	//2.迭代器区间初始化
	unordered_map<int, int> m2(m1.begin(), m1.end());
	//3.拷贝构造
	unordered_map<int, int> m3(m1);
}

5.2 unordered_map的迭代器

成员函数功能
begin获取容器中第一个元素的迭代器
end获取容器中最后一个元素下一个位置的正向迭代器

一般而言unordered_map并不支持反向迭代器,其次这些函数也与其他容器的迭代器成员函数无论是功能还是用法都是一模一样的,所以上手可谓十分简单。

void Test7()
{
	unordered_map<int, string> m;
	m.insert(pair<int, string>(1, "one"));
	m.insert(pair<int, string>(2, "two"));
	m.insert(pair<int, string>(3, "three"));
	//正向迭代器
	unordered_map<int, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
}

image.png

5.3 unordered_map的常见成员函数

unordered_mapunordered_set的成员函数类似,只不过多了一个[]运算符重载。

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数
[]运算符重载返回key所对应的val
void Test8()
{
	unordered_map<int,string> m1;
	//插入元素并去重
	m1.insert(make_pair(1,"one"));
	m1.insert(make_pair(1,"one"));
	m1.insert(make_pair(2, "two"));
	m1.insert(make_pair(2, "two"));
	m1.insert(make_pair(3, "three"));
	m1.insert(make_pair(3, "three"));
	unordered_map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
	it = m1.find(1);
	//如果找不到返回end()
	if (it != m1.end())
	{
		m1.erase(1);
	}
	it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
	//容器中值为2的元素个数
	cout << "容器中值为2的元素个数" << m1.count(2) << endl;
}

image.png

void Test9()
{
	unordered_map<int,string> m1;
	m1.insert(pair<int, string>(1, "one"));
	m1.insert(pair<int, string>(2, "two"));
	m1.insert(pair<int, string>(3, "three"));
	//容器大小
	cout << m1.size() << endl;
	//清空容器
	m1.clear();
	//容器判空
	cout << m1.empty() << endl;
	unordered_map<int, string> tmp;
	tmp.insert(pair<int, string>(4, "four"));
	tmp.insert(pair<int, string>(5, "five"));
	tmp.insert(pair<int, string>(6, "six"));
	//交换两个容器的数据
	m1.swap(tmp);
	unordered_map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << "<" << it->first << "," << it->second << ">" << " ";
		++it;
	}
	cout << endl;
}

image.png
值得注意的是:unordered_map的插入与删除操作可能存在迭代器失效的问题。

6. unordered_multimap

unordered_multimap的使用方式与unordered_map基本一致,唯一的区别就在于unordered_multimap允许键值冗余,即可存储重复元素。

void Test9()
{
	//允许键值冗余
	unordered_multimap<int, string> m;
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(1, "1"));
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(2, "2"));
	m.insert(make_pair(3, "three"));
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; 
}

image.png
值得注意的是:unordered_multimapfind返回底层哈希表中第一个找到的键值为key的键值对的迭代器,而unordered_map返回的是key元素的迭代器。并且由于unordered_multimap支持键值冗余,所以其成员函数没有[]运算符重载,因为一旦键值容易,根本不知道该返回哪个键值的value

思考题:为什么unordered_map/unordered_set存在迭代器失效的问题,而map/set就没有呢?

其实这种说法并不准确,因为unordered_map/unordered_set通常是基于哈希表实现,哈希表插入或删除时可能需要移动桶中的元素(扩容)或重新链接元素(扩容或删除桶中元素),这个操作会导致指向这些桶的迭代器失效。而map/set通常基于红黑树实现,红黑树的删除操作只涉及树节点的重新链接和旋转,不影响其他节点的内存位置。所以插入/删除操作不会导致对其他节点迭代器失效(但是指向该删除节点的迭代器是失效的)。

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

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

相关文章

使用MVC设计模式根据软件系统设计建设高校数字化教育教学资源共享平台

目录 案例 【题目】 【问题 1】(9 分) 【问题 2】(6 分) 【问题 3】(10 分) 答案 【问题 1】答案 【问题 2】答案 【问题 3】解析 相关推荐 案例 阅读以下关于软件系统设计的叙述&#xff0c;在答题纸上回答问题 1 至问题 3。 【题目】 某软件企业受该省教育部门委托…

【SpringCloud Alibaba】(九)学习 Gateway 服务网关

目录 1、网关概述1.1、没有网关的弊端1.2、引入 API 网关 2、主流的 API 网关2.1、NginxLua2.2、Kong 网关2.3、Zuul 网关2.4、Apache Shenyu 网关2.5、SpringCloud Gateway 网关 3、SpringCloud Gateway 网关3.1、Gateway 概述3.2、Gateway 核心架构 4、项目整合 SpringCloud …

【妙招大放送】:苹果手机数据恢复的4个技巧来啦!

手机是我们日常生活中不可或缺的一部分&#xff0c;它存储着照片、视频、联系人等许多重要的数据。但是&#xff0c;意外时有发生&#xff0c;我们有时会因为软件崩溃或者是手机损坏等的原因导致这些重要的数据丢失。那么&#xff0c;对于苹果用户来说&#xff0c;苹果手机数据…

电源技术中的深力科强力推荐一款低功耗、高效率同步降压变换器SiLM6609 致力于为您提供高品质电源技术解决方案

在能源紧张且智能化技术高速发展的当下&#xff0c;电源是电子设备不可或缺的核心。电源的质量和效率直接关系到设备的稳定运行和能耗控制&#xff0c;对于提高设备性能和降低运营成本至关重要。 为应对现代电子设备对性能与能耗的严苛要求&#xff0c;SiLM6609——低功耗、高…

.NET 一款通过白名单程序执行命令的工具

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

Adobe Photoshop PS v25.6 下载安装教程(PS下载)

前言 Adobe Photoshop 是一款专业强大的图片处理工具&#xff0c;从照片编辑和合成到数字绘画、动画和图形设计&#xff0c;一流的图像处理和图形设计应用程序是几乎每个创意项目的核心所在。利用 Photoshop 在桌面上的强大功能&#xff0c;您可以在灵感来袭时随时随地进行创作…

vue2使用electron-builder打包-使用electron的api实现文件下载

本项目用的是vue2版本开发&#xff0c;最后使用electron-builder打包成桌面应用程序 一、需求描述 1、用户点击按钮&#xff0c;下载html文件 2、代码 exportHtml() { //.html是放在public文件夹下面的本地文件axios.get("/html/合同模板.html").then(res > {let…

网络通信和TCP/IP协议详解

目录 网络协议 一、计算机网络是什么&#xff1f; 定义和分类 计算机网络发展简史 二、计算机网络体系结构 OSI 七层模型 TCP/IP 模型 TCP/IP 协议族 IP、TCP 和UDP TCP/IP 网络传输中的数据 地址和端口号 MAC 地址 IP 地址 端口号 综述 三、TCP 特性 TCP 三次握…

2024最新影视视频APP源码/猕猴桃影视系统源码/独立后台(支持安卓端+苹果端)

源码简介&#xff1a; 最新影视视频APP源码&#xff0c;它是猕猴桃影视系统源码&#xff0c;它有个独立的后台&#xff0c;无论你是安卓还是苹果用户&#xff0c;都能轻松使用呢。 绿豆源码、绿豆影视、小乌2.1&#xff0c;还有猕猴桃影视。追影兔新版本的整体结构设计已经全…

Transformer模型-3-基本工作流程

继 《Transformer模型-2-模型架构》该文主讲Transformer的基本工作流程。 第一步: 获取输入句子某单词的向量X。 X&#xff1a;是指某单词的向量&#xff0c;transformer是分别计算word embedding和position embedding并将两者相加得到向量X。 Embedding Embeddings 是一种将现…

Spring-bean的循环依赖

文章目录 什么是Spring的循环依赖?Setter 方法循环依赖三级缓存Spring 是如何利用三级缓存解决 Bean 的循环依赖&#xff1f;有了三级缓存为什么还需要二级缓存&#xff1f; 构造器循环依赖总结 什么是Spring的循环依赖? 在 Spring 框架中&#xff0c;循环依赖是指两个或多个…

萌化人心的AI宠物视频:1条爆款35万赞,带你轻松涨粉10万(附教程)

萌宠系的小动物配上可爱的 BGM&#xff0c;场景情绪感直接拉满。用 AI 做超萌宠物视频&#xff0c;涨粉确实香&#xff0c; 分享一个有趣的 AI 宠物玩法&#xff0c;使用用 AI 生成超萌动物&#xff08;水獭&#xff09;&#xff0c;做成宠物互动的场景式&#xff0c;这种视频播…

掌握Go语言的基本数据类型:编程世界的ABC

Go语言以其精炼的语法和卓越的性能&#xff0c;正日益成为现代软件开发的关键驱动力。在Go语言的众多特性中&#xff0c;基本数据类型的重要性不言而喻&#xff0c;它们是构建任何复杂应用程序的基石。正如掌握任何新语言需从其基础元素开始&#xff0c;Go语言的学习同样始于对…

【qt】windows下qt连接数据库

1.新建数据库 create database mydatabase;2.新建表结构&#xff0c;并插入数据 3.qt下连接数据库 1.连接数据库&#xff0c;需要加sql 2.添加QsqlDatabase头文件&#xff0c;使用提示句柄&#xff0c;头文件QMessageBox 3.连接数据库 4.界面设计 5.插入实现 注意这里如果…

盛水最多的容器问题

目录 一题目概述&#xff1a; 二思路理解&#xff1a; 三解答代码&#xff1a; 一题目概述&#xff1a; leetcode链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 二思路理解&#xff1a; 首先这道题虽然看起来简单&#xff0c;很难不让人想到直接暴力破解它&a…

【操作系统】12.文件系统是怎么管理的?

2.文件系统是怎么管理的&#xff1f; 2.1 文件系统的实现 2.1.1 文件系统层次结构 用户调用接口 文件目录系统 存取控制验证模块 逻辑文件系统与文件信息缓冲区 物理文件系统 辅助分配模块 设备管理程序模块 2.1.2 目录实现 线性列表 哈希表 2.1.3 文件实现 文件分配方式 连续…

Unity射击游戏开发教程:(32)控制子弹射速

显示发射速度从较慢到较快的变化 这是一篇关于如何实现射速以防止玩家乱按射击按钮的快速文章。 通常做法 说到要控制子弹的射速,可以通过以下几种方法: 通过设置子弹的发射间隔时间来控制射速。在每次子弹发射后,设置一个时间延迟,确保下一枚子弹不能立即发射。 利用计时…

Redis下载安装使用教程图文教程(超详细)

《网络安全自学教程》 Redis下载安装使用 1、下载安装2、基础配置2.1、远程连接2、保护模式3、默认密码4、后台运行4.1 验证服务是否启动4.2 停止服务 1、下载安装 1&#xff09;到Redis中文网 https://www.redis.com.cn/download.html 下载Redis安装包 2&#xff09;Redis的安…

市场动荡!宝马「赶超」特斯拉?华为打响高阶智驾「价格战」

新能源汽车市场正在进入动荡期。 本周&#xff0c;欧洲市场传来重磅消息&#xff0c;宝马在欧洲的电动汽车销量首次超过特斯拉。根据JATO Dynamics的数据&#xff0c;7月宝马在欧洲本土市场销售了14,869辆电动汽车&#xff0c;以308辆的微弱优势首次超过特斯拉。 数据显示&…

“蓝屏事件”阴魂不散,微软安全更新导致 Linux 系统无法启动即解决方案

最近&#xff0c;众多Linux用户报告称他们的设备在尝试启动时&#xff0c;收到了一条神秘的错误消息&#xff1a;“系统出了严重问题。”这起事件的罪魁祸首是微软在月度安全更新中发布的一个补丁&#xff0c;用于修复一个存在已久的GRUB漏洞。 这次更新却导致了Linux和Windows…