std::unorderd_map 简介

1. unorderd_map 简介

  • 1. unorderd_map 简介
    • 简介
    • 1.1. 实现原理
    • 1.2. 函数
    • 1.3. 问题集
      • 1.3.1. emplace、emplace_hint、insert 的区别
    • 1.4. 参考链接

简介

  • unordered_map 是 C++ 标准库中的一个容器,它定义在 <unordered_map> 头文件里。它借助哈希表来存储键值对,能快速查找、插入和删除元素
  • 快速查找:平均情况下,查找、插入和删除操作的时间复杂度为 O ( 1 ) O(1) O(1)。不过在最坏情况下,例如哈希冲突严重时,时间复杂度会达到 O ( n ) O(n) O(n)
  • 无序存储:unordered_map 不会按照键的顺序存储元素,元素的存储顺序由哈希函数决定。
  • 键的唯一性:每个键在 unordered_map 中是唯一的。若尝试插入已存在的键,新的值会覆盖旧的值。

1.1. 实现原理

  • 底层实现主要基于哈希表(Hash Table)
  1. 哈希函数
  • unordered_map 使用哈希函数将键转换为一个无符号整数,这个整数将作为数组的索引。
  • 对于基本数据类型(如 int、string 等),标准库已经提供了默认的哈希函数。
  • 但对于自定义类型,需要用户自己定义哈希函数。

例如,对于自定义类型 MyKey,可以这样定义哈希函数:

#include <functional>struct MyKey {int a;double b;// 重载相等运算符,用于比较键是否相等bool operator==(const MyKey& other) const {return a == other.a && b == other.b;}
};// 自定义哈希函数
struct MyKeyHash {std::size_t operator()(const MyKey& k) const {// 使用 std::hash 对不同成员进行哈希,然后组合auto h1 = std::hash<int>{}(k.a);auto h2 = std::hash<double>{}(k.b);return h1 ^ (h2 << 1);}
};
  1. 哈希桶(Bucket)
  • 哈希表通常由一个数组构成,数组中的每个元素称为一个哈希桶。
  • 每个哈希桶可以存储一个或多个键值对,当多个键通过哈希函数映射到同一个桶时,就会发生哈希冲突。
  1. 处理哈希冲突
  • 哈希冲突是指不同的键通过哈希函数映射到了同一个桶。
  • unordered_map 通常使用链地址法(Separate Chaining)来处理哈希冲突。
  • 在链地址法中,每个哈希桶实际上是一个链表(或其他容器,如红黑树),当发生哈希冲突时,新的键值对会被添加到对应的链表中。

以下是一个简单的示意图,哈希表数组:

+--------+--------+--------+
| Bucket0| Bucket1| Bucket2|
+--------+--------+--------+
| Node1  | Node3  | Node4  |
| Node2  |        |        |
+--------+--------+--------+

在这个示意图中,Bucket0 发生了哈希冲突,有两个键值对(Node1 和 Node2)被映射到了这个桶中,它们通过链表连接在一起。

  1. 插入操作
  • 向 unordered_map 中插入一个键值对时,会执行以下步骤:
  • 使用哈希函数计算键的哈希值。
  • 根据哈希值找到对应的哈希桶。
  • 检查该桶中是否已经存在相同的键,如果存在,则更新对应的值;如果不存在,则将新的键值对插入到桶中(通常是链表的头部)。
  1. 查找操作
  • 当查找一个键对应的值时,会执行以下步骤:
  • 使用哈希函数计算键的哈希值。
  • 根据哈希值找到对应的哈希桶。
  • 遍历该桶中的链表(或其他容器),查找是否存在与给定键相等的键。如果找到,则返回对应的值;如果未找到,则返回一个表示未找到的标记(如 end() 迭代器)。
  1. 删除操作
  • 删除操作与查找操作类似,首先找到对应的哈希桶,然后遍历桶中的链表,找到要删除的键值对并将其从链表中移除。
  1. 负载因子(Load Factor)和扩容
  • 负载因子是指哈希表中元素的数量与哈希桶数量的比值。
  • 当负载因子超过某个阈值(通常是 1.0)时,为了减少哈希冲突,提高查找效率,unordered_map 会进行扩容操作。
  • 扩容时,会创建一个更大的哈希表数组,然后将原有的键值对重新哈希到新的数组中。

总结:unordered_map 通过哈希表实现了快速的键值对查找、插入和删除操作。它使用哈希函数将键映射到哈希桶,通过链地址法处理哈希冲突,并在负载因子过高时进行扩容。这种实现方式使得 unordered_map 在平均情况下具有 O(1) 的时间复杂度。

1.2. 函数

  • 成员方法

  • 迭代器

    • begin 返回指向容器中第一个键值对的正向迭代器。
    • end 返回指向容器中最后一个键值对之后位置的正向迭代器。
    • cbegin 和 begin 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。
    • cend 和 end 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。
  • CRUD操作

    • operator[key] 该模板类中重载了 [] 运算符,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对。

    • at(key) 返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常。

    • find(key) 查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(end 方法返回的迭代器)。

    • count(key) 在容器中查找以 key 键的键值对的个数。

    • equal_range(key) 返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围。

    • emplace 向容器中添加新键值对,直接在容器内部构造元素,避免了不必要的拷贝或移动,效率比 insert 方法高。

    • emplace_hint 向容器中添加新键值对,接受一个迭代器 position 作为提示参数,用于提高插入效率,但提示错误可能会降低效率。

    • insert 向容器中添加新键值对,通常需要先构造好 value_type 对象,然后将其插入容器,可能会涉及额外的拷贝或移动操作。

    • erase 删除指定键值对。可以通过键、迭代器位置或迭代器范围来指定要删除的元素。

    • clear 清空容器,即删除容器中存储的所有键值对。

  • 属性

    • empty 若容器为空,则返回 true;否则 false。
    • size 返回当前容器中存有键值对的个数。
    • max_size 返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。
  • 类函数

    • swap 交换 2 个 unordered_map 容器存储的键值对,前提是必须保证这 2 个容器的类型完全相等。
  • 底层 hash 相关函数

    • bucket_count 返回当前容器底层存储键值对时,使用桶(一个线性链表代表一个桶)的数量。
    • max_bucket_count 返回当前系统中,unordered_map 容器底层最多可以使用多少桶。
    • bucket_size(n) 返回第 n 个桶中存储键值对的数量。
    • bucket(key) 返回以 key 为键的键值对所在桶的编号。
    • load_factor 返回 unordered_map 容器中当前的负载因子。负载因子,指的是的当前容器中存储键值对的数量(size)和使用桶数(bucket_count)的比值,即 load_factor = size / bucket_count。
    • max_load_factor 返回或者设置当前 unordered_map 容器的负载因子。
    • rehash(n) 将当前容器底层使用桶的数量设置为 n。
    • reserve 将存储桶的数量(也就是 bucket_count 方法的返回值)设置为至少容纳count个元(不超过最大负载因子)所需的数量,并重新整理容器。
    • hash_function 返回当前容器使用的哈希函数对象。

1.3. 问题集

1.3.1. emplace、emplace_hint、insert 的区别

  • 构造方式:
    • insert:通常需要先构造好 value_type 对象,然后将其插入容器,可能会涉及额外的拷贝或移动操作。
    • emplace 和 emplace_hint:直接在容器内部构造元素,避免了不必要的拷贝或移动,效率更高。
  • 提示参数:
    • insert 和 emplace:不需要提示参数。
    • emplace_hint:接受一个迭代器作为提示参数,用于提高插入效率,但提示错误可能会降低效率。
  • 返回值:
    • insert 和 emplace:返回一个 std::pair<iterator, bool>,表示插入是否成功。
    • emplace_hint:返回一个指向新插入元素或已存在元素的迭代器。
#include <iostream>
#include <unordered_map>int main() {std::unordered_map<int, std::string> myMap;auto result = myMap.insert({1, "one"});if (result.second) {std::cout << "Inserted successfully." << std::endl;} else {std::cout << "Element already exists." << std::endl;}return 0;
}
int main() {std::unordered_map<int, std::string> myMap;auto result = myMap.emplace(2, "two");if (result.second) {std::cout << "Emplaced successfully." << std::endl;} else {std::cout << "Element already exists." << std::endl;}return 0;
}
int main() {std::unordered_map<int, std::string> myMap;auto hint = myMap.begin();auto it = myMap.emplace_hint(hint, 3, "three");std::cout << "Inserted key: " << it->first << ", value: " << it->second << std::endl;return 0;
}

1.4. 参考链接

  • C++ STL unordered_map容器用法详解

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

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

相关文章

在线测试来料公差

UI 上图 V1 上图 V2 V3 Code import tkinter as tk from tkinter import messagebox, scrolledtext import socket import threading from datetime import datetime import os import logging from PIL import Image, ImageTk import subprocess# 定义文件夹路径…

【优秀三方库研读】【C++基础知识】odygrd/quill -- 折叠表达式

compute_encoded_size_and_cache_string_lengths 方法中这段代码是一个C的折叠表达式&#xff08;fold expression&#xff09;的应用&#xff0c;用于计算多个参数编码后的总大小。下面我将详细解释这段代码的每个部分&#xff0c;并说明为什么这样写。 代码如下&#xff1a; …

数据库安装和升级和双主配置

备份和导入数据 ./mysqldump -u root -p123321 test > test.sql rsync -av test.sql root192.168.0.212:/usr/local/mysql/ ./mysql -uroot -p test < …/test.sql sudo tar -zxvf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz -C /usr/local/ sudo ln -sfn /usr/loca…

【C语言】条件编译

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 条件编译 常用的预处理指令 核心应用场景 1.防止头文件重复包含 2.跨平台兼容性 3.调试模式与发布模式 4.功能开关 5.代码兼容性处理 结语 条件编译 一般情况下,源程序中所有…

如何在安卓平板上下载安装Google Chrome【轻松安装】

安卓平板可以通过系统内置的应用商店直接搜索并下载谷歌浏览器。用户打开平板上的“Play 商店”&#xff0c;在搜索框输入Google Chrome。出现结果后&#xff0c;点击第一个带有“Google LLC”字样的应用图标&#xff0c;然后点“安装”按钮。下载和安装时间和网速有关&#xf…

.NET代码保护混淆和软件许可系统——Eziriz .NET Reactor 7

.NET代码保护混淆和软件许可系统——Eziriz .NET Reactor 7 1、简介2、功能特点3、知识产权保护功能4、强大的许可系统5、软件开发工具包6、部署方式7、下载 1、简介 .NET Reactor是用于为.NET Framework编写的软件的功能强大的代码保护和软件许可系统&#xff0c;并且支持生成…

利用 SSE 实现文字吐字效果:技术与实践

利用 SSE 实现文字吐字效果:技术与实践 引言 在现代 Web 应用开发中,实时交互功能愈发重要。例如,在线聊天、实时数据监控、游戏中的实时更新等场景,都需要服务器能够及时将数据推送给客户端。传统的请求 - 响应模式在处理实时性要求较高的场景时显得力不从心,而 Server…

一个简单易用的密码生成器

基于浏览器的确定性密码生成工具&#xff0c;通过用户输入的网站名称和盐值生成符合安全要求的密码。特点&#xff1a; • 相同输入始终生成相同密码 • 密码自动包含大小写字母、数字和特殊符号 • 以字母开头&#xff0c;固定8位长度 • 完全在客户端运行&#xff0c;保护…

水上与水下遥控技术要点对比

1. 水上无人机遥控器技术要点 (1) 控制方式 多通道控制&#xff1a;通常使用2.4GHz或5.8GHz无线电信号&#xff0c;支持多通道&#xff08;如4通道以上&#xff09;分别控制飞行器的姿态&#xff08;俯仰、横滚、偏航&#xff09;和油门。 高级飞行模式&#xff1a;如定高模…

Android_SDK链接 雷神模拟器(端口问题) --- app笔记

调试环境&#xff1a;JDK&#xff08;java&#xff09; SDK&#xff08;android&#xff09; Node.js 雷神模拟器&#xff08;或 真机&#xff09; Appium&#xff08;Appium Server【内外件&#xff08;dos内件、界面化工具&#xff09;】、Appium Inspector&#xff09; p…

FreeRTOS【3】任务调度算法

重要概念 在运行的任务&#xff0c;被称为"正在使用处理器"&#xff0c;它处于运行状态。在单处理系统中&#xff0c;任何时间里只能有一个任务处于运行状态。 非运行状态的任务&#xff0c;它处于这 3 中状态之一&#xff1a;阻塞(Blocked)、暂停(Suspended)、就绪…

SLAM常用地图对比示例

序号地图类型概述1格栅地图将现实环境栅格化&#xff0c;每一个栅格用 0 和 1 分别表示空闲和占据状态&#xff0c;初始化为未知状态 0.52特征地图以点、线、面等几何特征来描绘周围环境&#xff0c;将采集的信息进行筛选和提取得到关键几何特征3拓扑地图将重要部分抽象为地图&…

【Vue】TypeScript与Vue3集成

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Vue 文章目录 1. 前言2. 环境准备与基础搭建2.1. 安装 Node.js 与 npm/yarn/pnpm2.2. 创建 Vue3 TypeScript 项目2.2.1. 使用 Vue CLI2.2.2. 使用 Vite&#xff08;推荐&#xff09;2.2.3. 目录结构简述 3. Vue3 TS 基础语法整…

高防IP是什么

"高防IP"是指"高防护IP"&#xff0c;是一种防御DDoS&#xff08;分布式拒绝服务攻击&#xff09;的网络安全服务。在分布式拒绝服务攻击中&#xff0c;攻击者会利用许多不同的计算机或者其他设备&#xff0c;通过向目标发送大量的网络请求来尝试使目标服务…

手机访问电脑端Nginx服务器配置方式

修改当前站点Nginx的配置如下。其中端口号必须是一个比较独特的端口号&#xff0c;比如8001。这样可以跟别的项目区分开来。域名使用0.0.0.0。 server {listen 80;listen 8001;server_name zfmap.cc 0.0.0.0;假设你电脑端的ip地址是192.168.1.101,那么你的手机与你的电脑连在同…

【算法】计数排序、桶排序、基数排序

算法系列八&#xff1a;非比较排序 一、计数排序 1.实现 1.1步骤 1.2代码 2.性质 2.1稳定性 2.1.1从前往后前始版&#xff1a; 2.1.2从后往前末始版&#xff1a; 2.2复杂度 2.2.1时间复杂度 2.2.2空间复杂度 二、桶排序 1.实现 1.1步骤 1.2代码 2.稳定性 三、…

JDK版本与Spring Boot版本之间对应关系

JDK&#xff08;Java Development Kit&#xff09;版本与Spring Boot版本之间存在一定的对应关系&#xff0c;选择合适的搭配对项目的稳定性、性能及功能实现至关重要&#xff0c;以下是详细介绍&#xff1a; 主要版本对应关系 Spring Boot版本发布日期支持的JDK版本备注3.2.…

如何检测Python项目哪些依赖库没有使用

要检测Python项目中哪些依赖库未被使用&#xff0c;可以采用以下方法&#xff1a; 1. 使用静态分析工具 vulture&#xff1a;静态分析工具&#xff0c;检测未使用的代码和导入 pip install vulture vulture your_project/pyflakes&#xff1a;检查未使用的导入语句 pip ins…

【智能指针】—— 我与C++的不解之缘(三十三)

一、智能指针的使用 还记得&#xff0c;在异常学习的时候&#xff0c;我们分析出了一个问题 double Divide(int x, int y) {if (y 0){throw string("the y is zero");}return (double)x / double(y); } void test(int x, int y) {int* arr new int[10];Divide(x,…

Hadoop+Spark 笔记 2025/4/21

读书笔记 定义 1. 大数据&#xff08;Big Data&#xff09; - 指传统数据处理工具难以处理的海量、高速、多样的数据集合&#xff0c;通常具备3V特性&#xff08;Volume体量大、Velocity速度快、Variety多样性&#xff09;。扩展后还包括Veracity&#xff08;真实性&#x…