【C++之unordered_set和unordered_map的介绍与应用】

C++学习笔记---024

  • C++之unordered_set和unordered_map的介绍与应用
    • 1、unordered_set和unordered_map的简单介绍
      • 1.1、unordered_set和unordered_map的基本概念
      • 1.2、unordered_set和unordered_map的基本特性
    • 2、unordered_set的基本操作
      • 2.1、unordered_set的定义
      • 2.2、unordered_set的基本接口使用
      • 2.3、unordered_multiset的基本介绍
    • 3、unordered_map的基本操作
      • 3.1、unordered_map的定义
      • 3.2、unordered_map的基本接口使用
      • 3.3、unordered_multimap的基本介绍
    • 4、map/set 和 unordered_map/unordered_set的区别
      • 4.1、性能测试
      • 4.2、总结

C++之unordered_set和unordered_map的介绍与应用

前言:
前面篇章学习了C++对于AVL树的知识认识和了解,接下来继续学习,C++的unordered_set和unordered_map等知识。
/知识点汇总/

1、unordered_set和unordered_map的简单介绍

1.1、unordered_set和unordered_map的基本概念

unordered_set 和 unordered_map 是 C++ 标准库中的两个关联容器,它们提供了基于哈希表的快速查找和插入操作。

unordered_set 是一个无序集合,它包含唯一的元素。换句话说,unordered_set 中的每个元素都是唯一的,并且没有重复。与 set 不同,unordered_set 不保证元素的排序,但通常提供了更快的插入和查找操作,因为它基于哈希表实现。
unordered_map 是一个无序关联数组(或哈希表),它存储键值对,并且每个键都是唯一的。与 map 不同,unordered_map 不保证元素的排序,但通常提供了更快的插入、删除和查找操作。

1.2、unordered_set和unordered_map的基本特性

unordered_set的基本特性:

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

unordered_map的基本特性:

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

2、unordered_set的基本操作

2.1、unordered_set的定义

void test_unordered_set1()
{// 构造一个空壳的us1的unordered_set的容器unordered_set<int> us1;// 插入几个值us1.insert(1);us1.insert(2);us1.insert(3);us1.insert(4);// 拷贝构造unordered_set<int> us2(us1);// 迭代器区间构造unordered_set<int> us3(us2.begin(), us2.end());// for循环打印一下for (auto& e : us3){cout << e << " ";}cout << endl;
}

2.2、unordered_set的基本接口使用

void test_unordered_set2()
{// 先构造一个空的容器unordered_set<int> us1;// 插入元素(只有这一种插入法)us1.insert(1);us1.insert(2);us1.insert(3);us1.insert(1);us1.insert(4);us1.insert(5);// 遍历容器第一种方法:迭代器遍历unordered_set<int>::iterator it = us1.begin();while (it != us1.end()){cout << *it << " ";++it;}cout << endl; // 1 2 3 4 5// 遍历容器第二种方法:for循环for (auto& e : us1){cout << e << " ";}cout << endl; // 1 2 3 4 5// 删除元素的方式一:直接找到值进行删除us1.erase(1);// 删除元素的方法二:利用迭代器进行删除unordered_set<int>::iterator pos = us1.find(2);if (pos != us1.end()){us1.erase(pos);}// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl; // 3 4 5// 判断容器是否为空cout << us1.empty() << endl; // 0// 获取值为3的个数cout << us1.count(3) << endl; // 1// 查看当前容器的容量cout << us1.size() << endl; // 3// 交换数据unordered_set<int> tmp{99, 88, 77, 66};us1.swap(tmp);// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl; // 99 88 77 66 // 打印一下for (auto& e : tmp){cout << e << " ";}cout << endl; // 3 4 5// 清空us1.clear();// 打印一下for (auto& e : us1){cout << e << " ";}cout << endl;  //   
}

2.3、unordered_multiset的基本介绍

大致实现的功能与unordered_map相同,但唯一不同的一点是在于这个多功能的set是允许值进行重复的!

这个多功能的set是相较于普通set来讲的count函数是返回的个数,而普通set的count函数是如果存在则返回1,不存在则返回0。
这个多功能set相较于普通set来讲的find函数是返回底层哈希表中第一个找到的键值为val的元素的迭代器,而普通set则是返回简单的key。

void test_unordered_set3()
{unordered_multiset<int> ums1;ums1.insert(1);ums1.insert(2);ums1.insert(4);ums1.insert(3);ums1.insert(1);ums1.insert(5);ums1.insert(2);ums1.insert(7);for (auto& e : ums1){cout << e << " ";}cout << endl;  // 1 1 2 2 3 4 5 7
}

3、unordered_map的基本操作

3.1、unordered_map的定义

void test_unordered_map1()
{// 构造一个空的key为int,value为double的unordered_mapunordered_map<int, double> um1;// 给um1赋上值um1.insert(make_pair(1, 1.1));um1.insert(make_pair(2, 2.2));um1.insert(make_pair(3, 3.3));um1.insert(make_pair(4, 4.4));// 拷贝构造unordered_map<int, double> um2(um1);// 迭代器区间拷贝um2的一段unordered_map<int, double> um3(um2.begin(), um2.end());// for循环打印一下um3,um3没问题则um1和um2都没问题for (auto& e : um3){cout << e.first<< "=>" << e.second << " ";}cout << endl;
}

3.2、unordered_map的基本接口使用

void test_unordered_map2()
{// 构造一个空的key为int,value为string的unordered_mapunordered_map<int, string> um1;// 插入方法一:构造匿名对象插入um1.insert(pair<int, string>(1, "111"));um1.insert(pair<int, string>(2, "222"));um1.insert(pair<int, string>(3, "333"));// 插入方法二:调用make_pair插入um1.insert(make_pair(4, "444"));um1.insert(make_pair(5, "555"));um1.insert(make_pair(6, "666"));// 插入方法三:用operator[]um1[7] = "777";um1[8] = "888";um1[9] = "999";um1[10] = "000";// 遍历方式一:利用迭代器进行遍历打印//unordered_map<int, string>::iterator it = um1.begin();auto it = um1.begin();while (it != um1.end()){cout << (*it).first << "=>" << (*it).second << " ";++it;}cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000// 遍历方法二:利用for循环进行遍历打印for (auto& e : um1){cout << e.first<< "=>" << e.second << " ";}cout << endl; // 1=>111 2=>222 3=>333 4=>444 5=>555 6=>666 7=>777 8=>888 9=>999 10=>000// 删除操作1:根据键值对key删除um1.erase(5);// 删除操作2:根据迭代器进行删除unordered_map<int, string>::iterator rit = um1.find(7); // 顺带使用键值对key就可以用find函数了if (rit != um1.end()){um1.erase(rit);}// 遍历打印一下,用for循环方便快捷一点for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl; // 1=>111 2=>222 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000// 修改键值对:通过find获得迭代器进行修改auto pos = um1.find(1);if (pos != um1.end()){pos->second = "11/11";}// 修改键值对:通过operator[]运算符重载进行修改um1[2] = "22/22";// 打印一下for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl; // 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000// 判空cout << um1.empty() << endl; // 0 -- 不空// 计算容器的大小cout << um1.size() << endl; // 8个// 计算容器中键值对的大小cout << um1.count(3) << endl; // 1// 交换两容器中的数据unordered_map<int, string> tmp{{11, "123"}, { 22, "345" }};um1.swap(tmp);for (auto& e : tmp){cout << "tmp=>" << " ";cout << e.first << "=>" << e.second << " ";}cout << endl; // tmp=> 1=>11/11 2=>22/22 3=>333 4=>444 6=>666 8=>888 9=>999 10=>000for (auto& e : um1){cout << "um1=>" << " ";cout << e.first << "=>" << e.second << " ";}cout << endl; // um1=> 11=>123 22=>345// 清空um1.clear();for (auto& e : um1){cout << e.first << "=>" << e.second << " ";}cout << endl;
}

重点讲一下[]:
1、若当前容器中已经存在着键值为key的键值对,则返回该键值对value的引用。
2、若当前容器中没有键值为key的键值对,则先插入键值对<key, value()>,然后再返回该键值对中value的引用。

3.3、unordered_multimap的基本介绍

这个容器与unordered_map基本一致,这两个的区别在于multimap允许键值对的冗余,也就是可以允许key和value有不同的值。
存在以下几个区别:find、count、operator[]接口功能
(1)find:

unordered_map 返回键值为key的键值对的迭代器
unordered_multimap 返回底层哈希表中第一个找到的键值为key的键值对的迭代器

(2)count:

unordered_map 键值为key的键值对存在则返回1,不存在则返回0(find成员函数可替代)
unordered_multimap 返回键值为key的键值对的个数(find成员函数不可替代)

(3)operator[]:

我们在unordered_multimap中是没有这个operator[]重载的,因为这个容器中是可以冗余的,所以我们不确定找的是哪一个,会导致很多的错误,所以我们的unordered_multimap是没有operator[]这个的!

void test_unordered_map3()
{unordered_multimap<int, string> ummp1;ummp1.insert(make_pair(2023, "yes"));ummp1.insert(make_pair(2023, "no"));ummp1.insert(make_pair(2023, "before"));ummp1.insert(make_pair(2023, "now"));for (auto& e : ummp1){cout << e.first << "=>" << e.second << " ";}cout << endl;
}

4、map/set 和 unordered_map/unordered_set的区别

在这里插入图片描述

4.1、性能测试

#include <iostream>
#include <set>
#include <unordered_set>
#include <time.h>
using namespace std;int main()
{int N = 1000;vector<int> v;v.reserve(N);srand((unsigned int)time(NULL));//随机生成N个数字for (int i = 0; i < N; i++){v.push_back(rand());}//将这N个数插入set容器set<int> s;clock_t begin1 = clock();for (auto e : v){s.insert(e);}clock_t end1 = clock();//将这N个数插入unordered_set容器unordered_set<int> us;clock_t begin2 = clock();for (auto e : v){us.insert(e);}clock_t end2 = clock();//分别输出插入set容器和unordered_set容器所用的时间cout << "set insert: " << end1 - begin1 << endl;cout << "unordered_set insert: " << end2 - begin2 << endl;//在set容器中查找这N个数clock_t begin3 = clock();for (auto e : v){s.find(e);}clock_t end3 = clock();//在unordered_set容器中查找这N个数clock_t begin4 = clock();for (auto e : v){us.find(e);}clock_t end4 = clock();//分别输出在set容器和unordered_set容器中查找这N个数所用的时间cout << "set find: " << end3 - begin3 << endl;cout << "unordered_set find: " << end4 - begin4 << endl;//将这N个数从set容器中删除clock_t begin5 = clock();for (auto e : v){s.erase(e);}clock_t end5 = clock();//将这N个数从unordered_set容器中删除clock_t begin6 = clock();for (auto e : v){us.erase(e);}clock_t end6 = clock();//分别输出将这N个数从set容器和unordered_set容器中删除所用的时间cout << "set erase: " << end5 - begin5 << endl;cout << "unordered_set erase: " << end6 - begin6 << endl;return 0;
}

在这里插入图片描述

4.2、总结

(1)、map 和 set:

  1. 优点

有序性:由于红黑树的特性,map和set中的元素都是有序的,这在很多应用中都会简化操作。
检索效率:红黑树的检索效率较高,通常可以达到O(log N)的时间复杂度。

  1. 缺点

空间占用:由于红黑树需要维护树的平衡和节点的额外信息(如父节点、子节点、颜色等),因此相对于其他数据结构(如哈希表),map和set的空间占用率较高。

(2)、unordered_map 和 unordered_set

  1. 优点

查找速度:由于哈希表的特性,unordered_map和unordered_set的查找速度非常快,平均时间复杂度可以达到O(1)。
动态增长:unordered_map和unordered_set可以动态增长,并且可以通过size属性获取元素个数。

  1. 缺点

遍历顺序:由于哈希表的特性,unordered_map和unordered_set中的元素是无序的。因此,遍历它们的顺序可能与插入顺序不同。
哈希表建立:虽然哈希表的查找速度很快,但是哈希表的建立过程(即哈希函数的计算和哈希表的初始化)可能会比较耗时。

(3)、性能总结

1.查找速度:对于查找操作,unordered_map/unordered_set 通常比 map/set 快,因为哈希表的查找时间复杂度通常为O(1),而红黑树的查找时间复杂度为O(log N)。
2.有序性:如果需要保持元素的顺序,map/set 是更好的选择,因为它们是基于红黑树实现的,可以提供有序的键值对或元素存储。
3.空间占用:由于红黑树需要维护额外的信息,因此 map/set 的空间占用率通常高于 unordered_map/unordered_set。
4.遍历顺序:如果遍历顺序很重要,且需要按照插入顺序遍历,那么应该选择 Set 或 Map,因为 unordered_map/unordered_set 的遍历顺序可能与插入顺序不同。

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

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

相关文章

Mysql迁移数据报错:1114 – The table ‘xxxx’is full问题以及迁移mysql

今天用Navicat迁移数据的时候&#xff0c;报了一个错:1114 – The table ‘xxxx’is full 解决方案一:修改mysql的配置 这个问题可能是2种原因: 1.存放数据的磁盘整的已经放满&#xff0c;不能再写入数据&#xff0c;需要优化磁盘的存储大小。2.超过了mysql的临时表大小 和内…

顶顶通语音信箱手机助手拦截方案

在电话自动外呼系统&#xff0c;常见的问题是被叫号码开通了语音信箱&#xff0c;或者运营商自动给开通了小秘书服务&#xff0c;一旦电话打不通&#xff0c;就会先播放一个类似这样的提示音&#xff0c;你拨打的电话已经开启了来电小秘书&#xff0c;请在滴声后留言。还有一个…

【面试题】IPS(入侵防御系统)和IDS(入侵检测系统)的区别

IPS&#xff08;入侵防御系统&#xff09;和IDS&#xff08;入侵检测系统&#xff09;在网络安全领域扮演着不同的角色&#xff0c;它们之间的主要区别可以归纳如下&#xff1a; 功能差异&#xff1a; IPS&#xff1a;这是一种主动防护设备&#xff0c;不仅具备检测攻击的能力&…

优思学院|如何管理库存?让浪费和缺货减至最少?

引言&#xff1a;库存在精益生产中的悖论 在精益生产管理中&#xff0c;库存&#xff08;Inventory&#xff09;一直被视为八大浪费之一&#xff0c;因为它占用了资源、空间&#xff0c;并且可能掩盖流程中的问题。然而&#xff0c;库存并非一无是处&#xff0c;特别是在流程尚…

这几类热销品被Ozon限制销售,ozon还有什么产品好卖?

OZON是俄罗斯最大的B2C电商平台&#xff0c;占据俄罗斯电商市场份额的62%&#xff0c;日均订单量高达37万单&#xff0c;拥有超过1600万的活跃用户。ozon平台对中国卖家招商的产品品类涵盖了多个领域&#xff0c;但近日Ozon官方发布将对这三大类目实行销售限制&#xff0c;一起…

微信小程序渲染层与逻辑层交互原理

1. 网页开发与小程序开发有何不同&#xff1f; 2. 小程序运行环境 3. 页面渲染技术选型 1. 纯客户端技术&#xff1b; 2. 纯Web技术&#xff1b; 3. 用客户端原生技术与Web技术结合的混合技术&#xff08;Hybrid&#xff09;&#xff0c;小程序就是使用的这种技术&#xff1…

MacBook关闭谷歌浏览器双指左右移动(扫动)前进后退功能

这个功能真的很反人类&#xff0c;正常上下滑动页面的时候很容易误操作&#xff0c;尤其是当你在一个页面上做了很多的编辑工作后误触发了此手势&#xff0c;那真叫一个崩溃&#xff01; 其实这应该是 Macbook 触控板提供的一个快捷操作&#xff0c;跟浏览器本身估计没关系&am…

基于大模型构建企业私有智能知识库落地的简单实践

​ 随着人工智能技术的飞速发展&#xff0c;大模型在企业知识管理中的应用日益广泛。下文是作者围绕如何基于大模型技术构建企业私有知识库&#xff0c;以提升企业的知识管理效率和创新能力的一些思考和简单实践。 ​ 本文对企业知识库的落地场景暂不作广泛的展开&#xff0c;…

成都百洲文化传媒有限公司网上开店怎么样?

在电商的浪潮中&#xff0c;每一个品牌都在寻找自己的定位与突破。而成都百洲文化传媒有限公司&#xff0c;正是这场浪潮中的一股强大助力&#xff0c;凭借其专业的电商服务&#xff0c;助力无数品牌实现了飞跃发展。 一、专业铸就品质&#xff0c;服务成就品牌 成都百洲文化传…

Runway:Gen-3 Alpha 文生视频现已开放

Runway 自 6 月 17 号公布 Gen-3 Alpha 快半个月了, 现在终于对所有人开放了&#xff0c;当然前提是你至少订阅了标准版&#xff08;12 美刀/月), 传送门&#xff1a;runwayml.com

中原汉族与北方游牧民族舞蹈文化在这段剧中表现得淋漓尽致,且看!

中原汉族与北方游牧民族舞蹈文化在这段剧中表现得淋漓尽致&#xff0c;且看&#xff01; 《神探狄仁杰》之使团喋血记是一部深入人心的历史侦探剧&#xff0c;不仅以其曲折离奇的案情和狄仁杰的睿智形象吸引观众&#xff0c;更以其对唐代文化的精准再现而备受赞誉。#李秘书讲写…

引力波信号的连续小波变换(Python)

提到引力波&#xff0c;就要提到引力波天文学。引力波天文学是观测天文学的一个新兴分支&#xff0c;主要利用引力波&#xff08;微小时空扭曲&#xff09;观测发出引力辐射的天体系统&#xff0c;比如中子星和黑洞等波源、超新星等事件以及大爆炸后不久的早期宇宙演化过程。 …

Java代码基础算法练习-计算平均身高-2024.07.02

任务描述&#xff1a; n个同学站成一排&#xff0c;求它们的平均身高 解决思路&#xff1a; 输入的学生人数为 for 循环次数&#xff0c;循环中每输入一个值就添加在总数中&#xff0c;循环结束总数除以对应的学生人数得到平均身高 代码示例&#xff1a; package a4_2024_07;…

泽州县和美环保科技有限公司——绿色环保的践行者

在环保产业蓬勃发展的今天&#xff0c;泽州县和美环保科技有限公司以其卓越的技术和强大的实力&#xff0c;成为山西省危废综合处置领域的翘楚。作为雅居乐环保集团的全资子公司&#xff0c;和美环保科技有限公司紧跟集团发展战略&#xff0c;致力于为社会提供全方位的环境服务…

JavaSE多线程线程池

文章目录 1. 多线程入门1.1 多线程相关概念1.2 什么是多线程1.3 多线程的创建方式1.3.1 继承 Thread 的方式1.3.2 实现 Runnable 接口的方式1.3.3 实现 Callable 接口的方式1.3.4 Thread 类中常用方法1.3.5 sleep() 方法 和 wait() 方法区别&#xff1a; 2. 线程安全2.1 线程安…

项目实战--Spring Boot + Minio文件切片上传下载

1.搭建环境 引入项目依赖 <!-- 操作minio的java客户端--> <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</version> </dependency> <!-- jwt鉴权相应依赖--> &…

Linux下编程之内存检查

前言 我们在进行编程时&#xff0c;有时不免会无意中写出一些容易导致内存问题&#xff08;可能一时表象上正常&#xff09;的代码&#xff0c;导致的后果肯定是不好的&#xff0c;就像一颗颗“哑弹”&#xff0c;令人心慌。网上推荐的辅助工具很多&#xff0c;此篇文章…

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理 目录 Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理 一、简单介绍 二、Unity Package 的目录结构 三、package.json 说明 四、程序集定义 1、程序集定义说明 …

在C#/Net中使用Mqtt

net中MQTT的应用场景 c#常用来开发上位机程序&#xff0c;或者其他一些跟设备打交道比较多的系统&#xff0c;所以会经常作为拥有数据的终端&#xff0c;可以用来采集上传数据&#xff0c;而MQTT也是物联网常用的协议&#xff0c;所以下面介绍在C#开发中使用MQTT。 安装MQTTn…

科普文:一文搞懂jvm实战(二)Cleaner回收jvm资源

概叙 在JDK9中新增了Cleaner类&#xff0c;该类的作用是用于替代finalize方法&#xff0c;更有效地释放资源并避免内存泄漏。 在JEP260提案中&#xff0c;封装了大部分Sun包内部的API之余&#xff0c;还引入了一些新的API&#xff0c;其中就包含着Cleaner这个工具类。Cleaner承…