【C++STL详解(十三)】unordered系列容器的介绍与使用

2024-08-30 18:44

本文主要是介绍【C++STL详解(十三)】unordered系列容器的介绍与使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

一、unordered_map

介绍

使用 

构造方式

修改 

容量

迭代器

元素访问

查询

桶操作 

二、unordered_set

介绍

使用

构造

修改

容量

 迭代器(只有单向)

查询

桶操作 

三、unordered系列的性能测试


前言

前面提到的map/set是C++98提供的关联式容器,底层结构是红黑树,最差情况下需要比较树得高度次,若树的结点十分多时,查询效率也不是很理想。C++11中,又提供了4个unordered系列容器,使用起来和map/set基本类似,只是底层结构不同。unordered系列底层是哈希结构(严格来说是哈希桶结构),最快的查询可以达到O(1)。

一、unordered_map

介绍

  • unordered_map是存储<key,value>键值对的关联式容器,KV模型
  • 键值key通常用于惟一地标识元素(不存在相同元素),而映射值是一个对象,其内容与此
    键关联。键和映射值的类型可能不同。
  • 内部没有任何的排序,是无序的,这点和map的最大区别,map有序
  • unordered_map通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭
    代方面效率较低。
  • 同样也支持operator【】访问
  • 底层是哈希桶结构
  • 迭代器是单向的,因为底层结构

使用 

使用上和map可以说是基本类似了!除了迭代器

构造方式

	unordered_map<string, int> m;//无参构造unordered_map<string, int> m1(m);//拷贝构造unordered_map<string, int> m2(m1.begin(), m1.end());//迭代器区间构造//初始化列表构造unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };

修改 

insert向容器中插入键值对
erase删除键值对
clear清空元素
swap交换两个容器内容
	unordered_map<int, int> m;//无参构造vector<int> a = {3,6,9,4,2,10};for (auto b : a){m.insert({ b,b });}m.erase(3);unordered_map<int, int> m1;m.swap(m1);m.clear();

容量

	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };m3.empty();//判空m3.size();//大小

迭代器

begin()返回第一个元素的迭代器
end()返回最后一个元素的下一个位置的迭代器
cbegin()返回第一个元素的const迭代器
cend()返回最后一个元素的下一个位置的const迭代器
	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };auto it = m3.begin();while (it!=m3.end()){cout << it->first << ":" << it->second << endl;++it;}

 注意:这个系列只提供单向迭代器!!

元素访问

operator【】:返回key对应的value的引用,和map一样!功能强大,既能插入又能修改!

	unordered_map<string, int> m3 ={ { "aa", 2 }, { "bb",3 } };m3["aa"] = 4;

查询

iterator find ( const key_type& k )放回key在哈希桶的位置
size_type count ( const key_type& k ) const;返回哈希桶中关键码为key的个数

注意:Key是唯一的,不允许重复,所以count为0/1!

	auto it = m3.find("aa");m3.count("aa");

桶操作 

bucket_count()返回桶的个数
bucket_size(n)返回n号桶中有效元素的总个数
bucket(key)返回元素key所在的桶号

二、unordered_set

介绍

  • unordered_set是存储key的关联式容器,K模型,底层可以看出<key,key>
  • 键值key通常用于惟一地标识元素(不存在相同元素)
  • 内部没有任何的排序,是无序的,这点和set的最大区别,set有序
  • unordered_set通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭
    代方面效率较低。
  • 底层是哈希桶结构
  • 迭代器是单向的,因为底层结构

使用

构造

和set基本一样,这里直接看实例就好了!

	unordered_set<int> s;//无参unordered_set<int> s1(s);//拷贝vector<int> a = { 3,6,9,4,2,10,3 };unordered_set<int> s2(a.begin(),a.end());//迭代区间//初始化列表unordered_set<int> s3 = { 6,7,1,2,4,9,10 };

修改

	unordered_set<int> m;//无参构造vector<int> a = {3,6,9,4,2,10};for (auto b : a){m.insert(b);}m.erase(3);unordered_set<int> m1;m.swap(m1);m.clear();

容量

	unordered_set<int> s3 = { 3,6,9,4,2,10,3 };s3.size();s3.empty();

 迭代器(只有单向)

	unordered_set<int> s3 = { 3,6,9,4,2,10,3 };auto it = s3.begin();while (it != s3.end()){cout << *it << endl;++it;}

查询

auto it = s3.find(3);
s3.count(3);// 0/1

桶操作 

bucket_count()返回桶的个数
bucket_size(n)返回n号桶中有效元素的总个数
bucket(key)返回元素key所在的桶号
	cout << s3.bucket_count() << endl;//统计桶的总数cout << s3.bucket_size(3) << endl;//返回3号桶中的数据个数cout << s3.bucket(3) << endl;//放回3所在的桶号

注意:还有两个容器这里就不过多介绍了,这几个容器使用起来差别不算很大,也比较简单,大家可以点击unordered_multiset和unordered_multimap查看,区别就是multi系列可以存在重复元素

三、unordered系列的性能测试

void test_set2()
{const size_t N = 1000000;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()); // N比较大时,重复值比较多//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;int m1 = 0;size_t begin3 = clock();for (auto e : v){auto ret = s.find(e);if (ret != s.end()){++m1;}}size_t end3 = clock();cout << "set find:" << end3 - begin3 << "->" << m1 << endl;int m2 = 0;size_t begin4 = clock();for (auto e : v){auto ret = us.find(e);if (ret != us.end()){++m2;}}size_t end4 = clock();cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << 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;}int main()
{test_set2();//test_map1();return 0;
}

大家可以copy到自己的编译器看看其他不同的结果,上述代码的结果如下:

可以看到unordered系列查找的速度确实快啊!因为底层的结构。


如果对你有那么一点帮助,欢迎点赞+收藏哦!

这篇关于【C++STL详解(十三)】unordered系列容器的介绍与使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121635

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三