【C++】unordered_map与unordered_set(系列关联式容器)

news2024/12/1 0:34:25

文章目录

  • 1.unordered系列关联式容器
  • 2. unordered_map
  • 3.unordered_set


1.unordered系列关联式容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,如map和set,它们在查询时效率可达logN,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率会降低。

因此在C++11中STL又提供了4个unordered系列的关联式容器,unordered_map,unordered_set和unordered_multimap,unordered_multiset,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。

在学习unordered_set和unordered_map之前最好先认识熟悉一下map和set,有关map和set的解释与用法,请移步至这篇文章:
map与set用法详解

那么在C++中unordered_map和map,unordered_set和set有什么区别呢?

最大的几个区别在于:底层结构,数据是否有序,在不同场景下的性能。

(C++98) set/map的底层结构是由红黑树(平衡二叉树搜索树)实现的,迭代器遍历(中序遍历),得到的数据是有序的,并且具有双向迭代器。在Java中,对它们的命名更直观,java中map和set,叫做TreeSet/TreeMap。

(C++11)unordered_set/unordered_map的底层结构是由哈希表实现的,迭代器遍历的结果是无序的,并且只有单向迭代器。关键点在于,unordered系列的关联式容器查找效率非常高,Hash表通过把关键码值映射到Hash表中的某个位置,来访问记录,查找的时间复杂度可达到O(1),在海量数据处理中有着广泛的应用。java中称之为HashSet/HashMap。

下面我们利用简单的代码,测试一下set与unordered_set的各个函数接口的性能。

#include <iostream>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <set>
#include <vector>
#include <time.h>
using namespace std;
int main()
{
	const size_t N = 10000;

	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 << s.size() << endl;
	cout << 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;

	return 0;
}

测试结果
在这里插入图片描述
总结一下:综合各种场景而言,unordered系列综合性能更好,尤其是find函数,查找效率一骑绝尘。在有序的情况下,set的插入和删除效率更好。

2. unordered_map

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_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。该函数中实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,将key对应的value返回。
  6. 它的迭代器至少是前向迭代器。

简单使用

void test_unordered_map()
{
	string arr[] = { "西瓜","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉","苹果","香蕉","梨" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		countMap[e]++;
	}

	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

测试结果:是无序的。

在这里插入图片描述

3.unordered_set

unordered_set官方文档
简单使用

void test_unordered_set()
{
	unordered_set<int> s;
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(7);
	s.insert(2);

	unordered_set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//支持范围for
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

测试结果:是无序的。

在这里插入图片描述

在文章结尾再次说明:unordered_set,unordered_map,以及map,set的key值是不允许重复的,如果需要有重复的key值,就使用unordered_multiset,unordered_multimap,以及muiltiset,multimap。

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

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

相关文章

【UnavailableInvalidChannel: The channel is not accessible or is invalid.】

Collecting package metadata (current_repodata.json): failedUnavailableInvalidChannel: The channel is not accessible or is invalid.channel name: simplechannel url: http://pypi.douban.com/simpleerror code: 404.condarc以点开头&#xff0c;一般表示 conda 应用程…

前端016_文章管理模块_列表功能

文章管理模块_列表功能 1、需求分析2、Mock模拟接口数据3、Api调用接口4、列表模版6、分页查询7、条件查询1、需求分析 文章管理模块主要进行对文章的增删改查,一篇文章可以选择多个标签。 首先开发模块中的列表功能,包含数据列表、分页、查询。 2、Mock模拟接口数据 请求…

『MySQL 实战 45 讲』14 - count(*) 慢的根本原因

count(*) 慢的根本原因 count(*) 的实现方式 MyISAM 引擎会把一个表的总行数存在了磁盘上InnoDB 引擎需要把数据一行行读出&#xff0c;累计计数 为什么 InnoDB 不跟 MyISAM 一样&#xff0c;也把数字存起来呢 由于多版本并发控制的原因&#xff08;和快照读有关系&#xf…

APP 兼容性测试是什么?8年测试老鸟告诉你

1、APP 兼容性测试认识 随着 APP 应用范围越来越广&#xff0c;用户群体越来越大&#xff0c;终端设备的型号也越来越多&#xff0c;移动终端碎片化加剧&#xff0c;使得 APP 兼容性测试成为测试质量保障必须要考虑的环节。 APP 兼容性测试通常会考虑&#xff1a;操作系统、厂…

Golang每日一练(leetDay0065)

目录 191. 位1的个数 Nnumber of 1-bits &#x1f31f; 192. 统计词频 Word Frequency &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 191. 位1的个数 Nnum…

《编程思维与实践》1070.复数幂

《编程思维与实践》1070.复数幂 题目 思路 思路比较简单,就是细节比较繁琐: ( a b i ) ( c d i ) ( a c − b d ) ( a d b c ) i (abi)(cdi)(ac-bd)(adbc)i (abi)(cdi)(ac−bd)(adbc)i , 利用该公式分实部和虚部进行计算结果即可. 由于涉及加减和正负号,所以在大整数结构…

MySQL的事务

1、事务的概念 事务是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这一组数据库命令要么都执行&#xff0c;要么都不执行。 事务是一个不可分割的工作逻辑单元&#xff…

【python数据分析】Pandas数据载入

&#x1f64b;‍ 哈喽大家好&#xff0c;本次是python数据分析、挖掘与可视化专栏第五期 ⭐本期内容&#xff1a;Pandas数据载入 &#x1f3c6;系列专栏&#xff1a;Python数据分析、挖掘与可视化 &#x1f44d;“总有一段时光悄悄过去然后永远怀念.” 文章目录 前言一、数据载…

fusion app 网页远程控制app

拥有此网页&#xff0c;即可。远程控制软件里面的公告更新以及其他内容。 网页并无联系方式&#xff0c;请自己摸索。 从此即可摆脱&#xff0c; QQ收藏&#xff0c;微云&#xff0c;讯飞语记的束缚&#xff01; 使用本程序网站放再多的内容都不会乱码&#xff01; FA2和1都可…

代码随想录算法训练营第四天|24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、面试题 02.07. 链表相交 、142.环形链表II

两两交换链表中的节点 题目链接&#xff1a;力扣 解题思路&#xff1a;虚拟头节点&#xff0c;然后进行模拟即可。 我拿到这道题的时候&#xff0c;其实交换的思路是有的&#xff0c;但是首先没有设虚拟节点&#xff0c;这使得我的解答很乱&#xff0c;有很多if条件判断。其次…

Eclipse中如何使用:Maven、Git、GitHub、码云

第1章 在Eclipse 中使用 Maven 1.1 安装 Maven 核心程序 1)下载地址&#xff1a;http://maven.apache.org/ 2)检查 JAVA_HOME 环境变量。Maven 是使用 Java 开发的&#xff0c;所以必须知道当前系统环境中 JDK 的安装目录。 即&#xff1a;安装jdk目录中bin目录的上一级目录…

基于ESP32的单通道LoRaWAN网关设计资料介绍-操作模式

资料下载链接》》 介绍 这是在由ESP8266/ESP32 mcu和sx1276无线电组成的平台上实现LoRa网关功能的第6代软件。与旧版本的网关不同&#xff0c;此版本将在单一频率上收听所有可用的扩频因子 (SF)。网关使用 Web 功能&#xff08;通过 Intranet&#xff09;启用网关的监控和配置…

桂院导航小程序 云开发项目 二次开发教程

Gitee代码仓库&#xff1a;桂院导航小程序 GitHub代码仓库&#xff1a;GLU-Guide​​​​​​​ 演示视频 桂院校园导航小程序 演示视频 先 假装 大伙都成功安装了云开发项目&#xff0c;并能在 微信开发者工具 和 手机 上正确运行。 接着就是 将项目 改成自己的学校。 代码…

Redis性能测试怎么做?看看字节8年测试工程师写的测试总结

最近测试服务端的时候,接触到了redis&#xff0c;之前也看过,但不系统,借着这次实践,记录一下 01、简介 Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。 它通常被称为数据结构…

【Linux】第一个驱动程序,hello world!开启驱动之旅

目录 前言&#xff1a; 一、背景 二、驱动程序编写流程 1.APP打开的文件在内核中如何表示&#xff1f; 2.编写驱动程序的流程 三、hello驱动程序实战 hello_drive.c hello_drive_test.c 最终测试&#xff1a; a.首先编译内核&#xff08;如果没有编译过&#xff09…

Makefile 与 docker 进行多服务 一次性构建

本机多服务一次性构建背景 本机开发多个服务,每个服务还会互相调用正常情况,开发者需要在本地启动多个服务,并且手动调用想着不使用gitlab ci/cd, 在本机快速通过 makefiledocker-compose 编排多个服务可执行源码在:https://github.com/webws/go-moda/tree/main/example/traci…

使用Segment Anything(SAM)模型进行自动标注

1.下载项目 项目1&#xff1a;https://github.com/zhouayi/SAM-Tool 项目2&#xff1a;https://github.com/facebookresearch/segment-anything git clone https://github.com/zhouayi/SAM-Tool.gitgit clone https://github.com/facebookresearch/segment-anything.git cd …

Nginx之正向代理与反向代理

1.什么是代理 打工人张三最近换了新工作&#xff0c;原来的住房离公司的路程太远&#xff0c;于是乎想要重新找一个离工作地不那么远的住房&#xff0c;由于工作繁忙&#xff0c;没有时间看房。 房东王五名下有2套住房&#xff0c;一套自己住&#xff0c;另一套想租出去&…

shell脚本----sed命令

文章目录 一、sed的工作流程二、sed的操作三、Sed命令使用3.1打印内容3.2删除行3.3替换3.4插入3.5分组调用 一、sed的工作流程 sed概述 sed编辑器时一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处理…

(转载)从0开始学matlab(第3天)—多维数组

正如我们所看到的&#xff0c;MATLAB 的数组可能是一维或多维的。一维的数组可以形象地看作一系列的数垂直地罗列起来&#xff0c;用一个下标就可以调用数组中的元素&#xff08;如图 a&#xff09;。这样的数组适用于一个变量的函数&#xff0c;例如在规定的时间间隔后一系列…