【STL十一】无序容器(哈希容器)—— unordered_map、unordered_set

2023-05-16

【STL十一】无序容器(哈希容器)—— unordered_map、unordered_set

  • 一、简介
    • 1、关联容器和无序容器不同
    • 2、无序容器特点
  • 二、头文件
  • 三、模板类
    • 四、无序容器的内部结构
    • 1、管理桶
    • 2、内部结构
  • 五、unordered_map成员函数
    • 1、迭代器
    • 2、元素访问
    • 3、容量
    • 4、修改操作
    • ~~5、操作~~
    • 5、查找
    • 6、桶接口
    • 7、哈希策略
  • 六、demo
    • 1、构造函数、emplace、find、迭代器
    • 2、桶接口bucket_count、max_bucket_count、bucket_size、bucket
  • 七、unordered_multimap
  • 八、unordered_set
  • 九、unordered_multiset。

  • 简介
    除了序列式容器和关联式容器之外,C++ 11 标准库又引入了一类容器,即无序容器。无序容器,又称无序关联式容器、或者哈希容器。

和关联式容器一样,此类容器存储的也是键值对元素;不同之处在于,关联式容器默认情况下会对存储的元素做升序排序,而无序关联式容器不会。
和其它类容器相比,无序关联式容器擅长通过指定键查找对应的值,而遍历容器中存储元素的效率不如关联式容器。

在这里插入图片描述

一、简介

无序容器包含有 4 个具体容器,分别为 unordered_map、unordered_multimap、unordered_set 以及 unordered_multiset。

无序容器功能
unordered_map存储键值对 <key, value> 类型的元素,其中各个键值对键的值不允许重复,且该容器中存储的键值对是无序的。
unordered_multimap和 unordered_map 唯一的区别在于,该容器允许存储多个键相同的键值对。
unordered_set不再以键值对的形式存储数据,而是直接存储数据元素本身(当然也可以理解为,该容器存储的全部都是键 key 和值 value 相等的键值对,正因为它们相等,因此只存储 value 即可)。另外,该容器存储的元素不能重复,且容器内部存储的元素也是无序的。
unordered_multiset和 unordered_set 唯一的区别在于,该容器允许存储值相同的元素。

1、关联容器和无序容器不同

和关联式容器一样,无序容器也使用键值对(pair 类型)的方式存储数据。不过,它们有本质上的不同:

  • 关联式容器的底层实现采用的树存储结构,更确切的说是红黑树结构;
  • 无序容器的底层实现采用的是哈希表的存储结构。

2、无序容器特点

基于底层实现采用了不同的数据结构,因此和关联式容器相比,无序容器具有以下 2 个特点:

  • 无序容器内部存储的键值对是无序的,各键值对的存储位置取决于该键值对中的键,
  • 和关联式容器相比,无序容器擅长通过指定键查找对应的值(平均时间复杂度为O(1));但对于使用迭代器遍历容器中存储的元素,无序容器的执行效率则不如关联式容器。

二、头文件

#include <unordered_map>
#include <unordered_set>

三、模板类

unordered_map 容器模板的定义如下所示:

template < class Key,                        //键值对中键的类型
           class T,                          //键值对中值的类型
           class Hash = hash<Key>,           //容器内部存储键值对所用的哈希函数
           class Pred = equal_to<Key>,       //判断各个键值对键相同的规则
           class Alloc = allocator< pair<const Key,T> >  // 指定分配器对象的类型
           > class unordered_map;

四、无序容器的内部结构

1、管理桶

  • 每一个位置,我们把其叫做一个桶。
  • 通过哈希函数映射时可能好几个值,映射到一个桶。
  • 如果桶的数量小的时候,可能会出现挂篮在的现象。(即一个桶下有好几个篮子——存储的对象)。这样我们找某个值时,先找到对应的桶,然在桶里再找我们桶内存储的值。
  • 管理桶:无序容器的性能依赖于哈希函数的质量和桶的数量大小

2、内部结构

中间黑色的代表桶

  • unordered_map 、unordered_multimap在这里插入图片描述
  • unordered_set、unordered_multiset
    在这里插入图片描述

五、unordered_map成员函数

1、迭代器

成员函数功能
begin()同array容器
end()同array容器
rbegin()同array容器)
rend()同array容器)
cbegin()同array容器
cend()同array容器
crbegin()同array容器)
crend()同array容器)

2、元素访问

成员函数功能
operator[]同array容器
at(n)同array容器
front()同array容器
back()同array容器
data()同array容器

3、容量

成员函数功能
size()同array容器
max_size()同array容器
empty()同array容器
reserve同vector容器
capacity同vector容器
shrink_to_fit同vector容器

4、修改操作

成员函数功能
clear()同vector容器
insert()同vector容器
insert_or_assign(C++17)同map容器
emplace()同vector容器
emplace_hint()同map容器
try_emplace(C++17)同map容器
erase()同vector容器
push_back()同vector容器
emplace_back()同vector容器
pop_back()同vector容器
push_front()同vector容器
emplace_front()同vector容器
pop_front()同vector容器
resize()同vector容器
swap()同vector容器
extract(C++17)从另一容器释出结点
merge(C++17)从另一容器接合结点

5、操作

成员函数功能
merge()list容器
splice()list容器
remove(val)list容器
remove_if()list容器
reverse()list容器
unique()list容器
sort()list容器

5、查找

成员函数功能
count(key)同map容器
find(key)同map容器
contains (C++20)同map容器
equal_range(key)同map容器
lower_bound(key)同map容器
upper_bound(key)同map容器

6、桶接口

成员函数功能
begin()同array容器
end()同array容器
cbegin()同array容器
cend()同array容器
bucket_count正在使用的桶的数目。
max_bucket_count()容器容纳的最多的桶的数量
bucket_size(n)第n个桶中有多少个元素
bucket(key)关键字为k的元素在哪个桶种

7、哈希策略

成员函数功能
load_factor每个桶的平均元素数量,返回float值
max_load_factor试图维护的平均桶大小,返回float值,会在需要时添加新的桶,以使得load_facotr < max_load_factor
rehash(n)重组存储,使得bucket_count >=n, 且bucket_count > size/max_load_factor
reserve(n)重组存储,使得可以保存n个元素且不必rehash。

六、demo

1、构造函数、emplace、find、迭代器

  • 返回值
    指向键等于 key 的元素的迭代器。若找不到这种元素,则返回尾后(见 end() )迭代器。
#include <iostream>
#include <string>       // string
#include<unordered_map>

using namespace std;
int main() {
    // 调用构造函数 1,也就是默认构造函数
    unordered_map <string, string> umap{
        {"小b","家在西安"},
        {"小a","家在北京"},
        {"小d","没有家"},
    };

    umap.emplace("小c","家在濮阳" );

    cout << "i can find 小c:" << endl;
    auto ite = umap.find("小c");
    cout << ite->first << "=" << ite->second << endl << endl;

    //使用迭代器输出 umap 容器存储的所有键值对
    for (auto iter = umap.begin(); iter != umap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
    return 0;
}

输出

i can find 小c:
小c=家在濮阳


小b 家在西安
小a 家在北京
小d 没有家
小c 家在濮阳
在这里插入图片描述

2、桶接口bucket_count、max_bucket_count、bucket_size、bucket

#include <iostream>
#include <string>       // string
#include<unordered_map>

using namespace std;
int main() {
    // 调用构造函数 1,也就是默认构造函数
    unordered_map <string, string> umap{
        {"小b","家在西安"},
        {"小c","家在濮阳"},
        {"小a","家在北京"},
        {"小d","没有家"},
    };

    //获取键为 小c的键值对所在的范围
    auto pair = umap.equal_range("小c");
    //输出 pair 范围内的每个键值对的键的值
    for (auto iter = pair.first; iter != pair.second; ++iter) {
        cout << iter->first << "="<<iter->second;
    }
    cout << endl;
    
    auto bc = umap.bucket_count();
    cout << "bucket_count = " << bc << endl;

    auto bcm = umap.max_bucket_count();
    cout << "max_bucket_count = " << bcm << endl;

    auto szie = umap.bucket_size(3);
    cout << "bucket_size(3) = " << szie << endl;

    auto pos = umap.bucket("小c");
    cout << "bucket(\"小c\") = " << pos << endl;

    return 0;
}

输出

小c=家在濮阳
bucket_count = 8
max_bucket_count = 1152921504606846975
bucket_size(3) = 1
bucket(“小c”) = 3

七、unordered_multimap

和 unordered_map 容器一样,unordered_multimap 容器也以键值对的形式存储数据,且底层也采用哈希表结构存储各个键值对。两者唯一的不同之处在于,unordered_multimap 容器可以存储多个键相等的键值对,而 unordered_map 容器不行。

无序容器中存储的各个键值对,都会哈希存到各个桶(本质为链表)中。而对于 unordered_multimap 容器来说,其存储的所有键值对中,键相等的键值对会被哈希到同一个桶中存储。

  • unordered_multimap 容器模板的定义如下所示:
template < class Key,      //键(key)的类型
           class T,        //值(value)的类型
           class Hash = hash<Key>,  //底层存储键值对时采用的哈希函数
           class Pred = equal_to<Key>,  //判断各个键值对的键相等的规则
           class Alloc = allocator< pair<const Key,T> > // 指定分配器对象的类型
           > class unordered_multimap;
  • demo
#include <iostream>
#include <string>       // string
#include<unordered_map>
using namespace std;
int main() {
    // 调用构造函数 1,也就是默认构造函数
    unordered_multimap <string, string> ummap{
        {"小b","家在西安"},
        {"小c","家在濮阳"},
        {"小a","家在北京"},
        {"小d","没有家"},
        {"小d","也没有家"},
    };

    //输出 ummap容器中存储键为 'b' 的键值对的数量
    cout << ummap.count("小d") << endl;

    for (auto iter = ummap.begin(); iter != ummap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
        cout << "ummap.bucket(iter->first) = " << ummap.bucket(iter->first)<<endl;
    }

    cout << "ummap.bucket_count() = " << ummap.bucket_count();

    return 0;
}

  • 输出

2
小b 家在西安
ummap.bucket(iter->first) = 0
小c 家在濮阳
ummap.bucket(iter->first) = 3
小a 家在北京
ummap.bucket(iter->first) = 1
小d 没有家
ummap.bucket(iter->first) = 2
小d 也没有家
ummap.bucket(iter->first) = 2
ummap.bucket_count() = 8

八、unordered_set

unordered_set 容器具有以下几个特性:

  • 不再以键值对的形式存储数据,而是直接存储数据的值;
  • 容器内部存储的各个元素的值都互不相等,且不能被修改。
  • 不会对内部存储的数据进行排序(这和该容器底层采用哈希表结构存储数据有关,可阅读《C++ STL无序容器底层实现原理》一文做详细了解);

对于 unordered_set 容器不以键值对的形式存储数据,读者也可以这样认为,即 unordered_set 存储的都是键和值相等的键值对,为了节省存储空间,该类容器在实际存储时选择只存储每个键值对的值。

  • unordered_set 容器的类模板定义如下:
template < class Key,            //容器中存储元素的类型
           class Hash = hash<Key>,    //确定元素存储位置所用的哈希函数
           class Pred = equal_to<Key>,   //判断各个元素是否相等所用的函数
           class Alloc = allocator<Key>   //指定分配器对象的类型
           > class unordered_set;
  • demo
#include <iostream>
#include <string>       // string
#include<unordered_set>
using namespace std;
int main() {
    unordered_set<string> uset{
        "小b",
        "小c",
        "小a",
        "小d",
    };

    auto ite = uset.insert("小e");
    cout << *(ite.first) << " " << ite.second << endl;

    unordered_set<string> set2;
    set2.insert(uset.begin(), uset.end());

    for (auto iter = set2.begin(); iter != set2.end(); ++iter) {
        cout << *iter << endl;
    }

    return 0;
}

  • 输出

小e 1
小b
小c
小a
小d
小e

九、unordered_multiset。

unordered_multiset 容器大部分的特性都和 unordered_set 容器相同,包括:

  • unordered_multiset 不以键值对的形式存储数据,而是直接存储数据的值;
  • 该类型容器底层采用的也是哈希表存储结构,它不会对内部存储的数据进行排序;
  • unordered_multiset 容器内部存储的元素,其值不能被修改。

和 unordered_set 容器不同的是,unordered_multiset 容器可以同时存储多个值相同的元素,且这些元素会存储到哈希表中同一个桶(本质就是链表)上。
读者可以这样认为,unordered_multiset 除了能存储相同值的元素外,它和 unordered_set 容器完全相同。

  • unordered_multiset 容器类模板的定义如下:
template < class Key,            //容器中存储元素的类型
           class Hash = hash<Key>,    //确定元素存储位置所用的哈希函数
           class Pred = equal_to<Key>,   //判断各个元素是否相等所用的函数
           class Alloc = allocator<Key>   //指定分配器对象的类型
           > class unordered_multiset;
  • demo
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
    std::unordered_multiset<int> umset{ 1,2,2,2,3,4,5 };
    cout << "multiset size = " << umset.size() << endl;
    cout << "multiset count(2) =" << umset.count(2) << endl;

    //删除容器中所有值为 2 的元素
    int num = umset.erase(2);
    cout << "删除了 " << num << " 个元素 2" << endl;
    //输出容器中存储的所有元素
    for (auto iter = umset.begin(); iter != umset.end(); ++iter) {
        cout << *iter << " ";
    }

    cout << "umset.bucket_count() = "<< umset.bucket_count();
    return 0;
}


  • 输出

multiset size = 7
multiset count(2) =3
删除了 3 个元素 2
1 3 4 5 umset.bucket_count() = 8

参考:
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/container

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STL十一】无序容器(哈希容器)—— unordered_map、unordered_set 的相关文章

  • Get 一个显示界面,与数采串口通信

    程序第一步 xff1a 显示 数据来源 xff0c CR1000数据采集器 xff0c 5秒采集并存储上传 第二步 xff1a 存储 TXT文档存储 xff0c 逗号分隔 xff0c 每月创建一个新的文件 xff0c 可以另存为excel文
  • UART通信协议

    UART通信协议 一 UART是什么 xff1f 1 同步串口通信 vs 异步串口通信2 串行通信 二 通信协议三 工作原理四 特点 一 UART是什么 xff1f 通用异步收发传输器 xff08 Universal Asynchronou
  • win10右下角的通知区域

    属性 gt 通知和操作 gt 选择在任务栏上显示哪些图标 gt
  • UART一对多通信的方法

    通常 xff0c uart为单对单通信 xff0c 当用到一对多时可以用RS485 然而有时候我们MCU的uart口只剩一个 xff0c 又要接多个uart的外围芯片 xff0c 这时如果转成RS485需要加多个485收发器 xff0c 成
  • 全网最全的 postman 工具使用教程

    正文如下 xff0c 如果觉得有用欢迎点赞 关注 postman是一款支持http协议的接口调试与测试工具 xff0c 其主要特点就是功能强大 xff0c 使用简单且易用性好 无论是开发人员进行接口调试 xff0c 还是测试人员做接口测试
  • 星际争霸1终于可以在win10上运行了

    win7的时候 xff0c 星际争霸1就不能运行 xff0c 只好装了个虚拟机 xff0c 在虚拟机里玩 刚刚更新到了win10 xff0c 总觉得在虚拟机里玩不是个事 xff0c 就去网上搜索 xff0c 终于发现了办法 在 StarCr
  • windows下编译opencv 3.4.0

    为了方便后期的调试 xff0c 自己动手编译opencv3 4 0 xff0c 这样有需要的时候还可以自己修改修改源代码 通常来说 xff0c 编译32位比较简单 xff0c 直接用cmake生成编译的工程就行了 xff0c 但64位就比较
  • opencv添加的新接口clearVec()的实现

    自己编译的opencv xff0c 之前文章有说添加了这个接口 xff0c 也有上传3 3 0版本添加这个接口之后编译好的库 xff0c 但是没有把实现过程展现出来 xff0c 导致有些朋友问我如何实现的 xff0c 今天把这个实现放出来
  • 苏泊尔电饭煲不工作的维修

    本篇文章与其说是维修 xff0c 倒不如说成是 拆 xff0c 因为维修相对容易 xff0c 但想拆开却很艰难 xff0c 大部分的时间都花在了拆的工作上面 老家伙的样子如下 型号为 xff1a CYSB50FC99 100 xff0c 铭
  • 萨克斯吹不响的解决办法

    刚开始吹萨克斯 xff0c 发现总是吹不响 看各种入门的文章 xff0c 很多都强调口型的重要性 xff0c 各文章说得也都差不多 xff0c 我仔细捉摸 xff0c 不断尝试 xff0c 似乎还是不得要领 特别是安装好之后 xff0c 很
  • vs2010制作安装工程

    这里的安装工程 xff0c 是指制作安装包 xff0c 而不是vs2010的安装包 用向导生成一个安装工程 xff0c 通常会直接打开一个文件编辑窗口 xff1a 这个窗口很容易编辑 xff0c 把所有要安装的文件拖到 应用程序文件夹 上
  • windows下编译ffmpeg源代码

    由于工作原因 xff0c 需要使用ffmpeg在windows下进行代码跟踪 于是 xff0c 上网找相关文章 xff0c 搜索出来有很多 xff0c 经过查看 xff0c 其中的一个英文网站是最好的 xff0c 网址 xff1a http
  • 注册控件失败之一:提示0x80040200错误的处理办法

    今天有客户反馈说控件无法注册 xff0c 晕 xff0c 这问题好容易困扰开发者以及客服人员 xff0c 但是环境千差万别 xff0c 很难做到完全自动化 出现的错误号码有很多 xff0c 但相对的0x80040200这个号码出现的概率较其
  • win10+ubuntu23.04双系统安装

    win10 win10先安装好 xff08 确保主板上各个螺丝稳定 xff0c 至少4对螺丝 43 铜柱 xff0c 否则会各种蓝屏 xff09 如果双系统安装失败了 xff0c 连win10都进不去了 xff0c 用原版ISO刻录的U盘或
  • 冷门指标移中平均线和多空指数的完美结合(一定要看)

    注 xff0c 原贴地址 xff1a http blog sina com cn s blog 7f0a6fa50101hyls html 在此谨以记录防止原帖无法打开为忧 冷门指标移中平均线和多空指数的完美结合 一定要看 xff09 20
  • LINUX下安装QT的惨痛经历

    安装QT的惨痛经历 目标 xff1a 2012 4月下旬 xff0c 计划开始在linux上安装QT和ffmpeg xff0c 准备摸索一下视频客户端的开发 以下是安装过程 由于没有额外的电脑 xff0c 所以使用了虚拟机安装 电脑上刚好有
  • Linux下CAN总线速率设置,socketCAN。

    背景 xff1a 飞思卡尔Freescale的ARM9处理器i MX25系列 socketCAN对于在Linux下操作CAN总线非常的快捷方便 xff0c 其配置方法和在Linux下对网卡的配置相似 xff0c 方法如下 xff1a 1 i
  • c++在Linux环境下的套接字Tcp通信例子(demo)

    demo包括服务端和客户端的通信 xff0c 发送端发送格式为先发送长度为5的字符串数据 xff0c 告知对方接下来的数据长度 xff0c 接收端首先接收到消息长度 xff0c 再根据消息长度接受接下来的消息 服务端 xff1a inclu
  • yolo_mark工具的使用

    之前自己编译了一下yolo mark用来标注样本 我编译时yolo mark依赖了opencv3 2 0 当时为了方便直接把yolo mark exe放到编译yolo的文件夹 现在要在其他地方使用 xff0c 就把所有文件整理出来 其中op
  • GStreamer与opencv实现rtsp推流

    文章目录 前言安装库代码总结 前言 最近工作遇到瓶颈了呀 xff01 xff01 xff01 公司分配给我的任务是deepstream部署 xff0c 太难了 xff0c gstreamer语言学的我头皮发麻 xff01 xff01 xff

随机推荐