数据结构:哈希表 | C++中的set与map
上回说到,红黑树是提升了动态数据集中频繁插入或删除操作的性能。而哈希表(Hash Table),则是解决了传统数组或链表查找数据必须要遍历的缺点。

哈希表
哈希表的特点就是能够让数据通过哈希函数存到表中,哈希函数能够将数据处理为表中位置的索引(这个就叫映射),然后将其存入。这样一来,我们查找数据的时候只要一通过哈希函数就可以得到该数据的索引,然后进行操作。
哈希函数有很多种实现方法。
1、直接定址法
数据本身就直接作为哈希地址(即位置索引)然后进行存放,好处就是不会产生哈希冲突。

可以看到我们的存入的数据是分散在表中的,只有3个数却占用了6个位置。这也是为什么哈希表又叫散列表。这种方法只适合数据集中的情况。
2、除留余数法
这是最经典的方法。通过指定一个除数,将我们的数据进行相除来得到哈希地址。

这种方法可以有效地减少空间浪费,将数据集中起来。但是如果像2、22这样的数就会产生哈希冲突。其解决方法之后会讲到。
3、平方取中法
这个通过将数据平方计算后,根据哈希表的大小取中间的几位数,这样更有机会让数据随机均匀分布在哈希表中。
如1234的平方为1522756,哈希表的大小是100,那么去中间3位,存入227的地址中。
现在谈谈如何解决哈希冲突,一般有两种方法。
1、开放寻址法(闲散列)
顾名思义就是让空地址向发生冲突的新数据开放,让其存进去。比如线性探测和二次探测。线性探测是指按照顺序将新数据排在原本哈希地址的后面,先+1,不行+2,依次类推。而二次探测就是把这些数进行了平方再加,向前后两方进行。

那我们如果一直发生冲突,导致哈希表大小不够用了怎么办?这里需要引入“负载因子”的概念。负载因子是一个比例,表示当哈希表中的数据比哈希表的大小超过负载因子时,哈希表需要扩容,一般为0.7。
2、链地址法(开散列)
哈希桶法,拉链法一般都是指这个。
就是把每个位置作为一个链表的头,如果发生冲突,就将其作为后继节点连接在该位置下面。

虽然这样的负载因子可以大于一(即不用扩容),但因为要存储指针,会造成更多的空间开销。
我们讨论哈希表时常常会谈到“键值对”。这里的“键 Key”就是钥匙的意思,可以通过键来获取哈希地址。所以我们上文所操作的所有数据,都可以叫做键,关键码值常常也说的是这个。而另一个“值 Value”指的是与键关联的数据,其存在真正赋予了哈希表以灵活性与实用性,因为键一旦在哈希表中确认就不便更改了,而值可以随便的更新删除。所以键更像成为了值的索引,从而适应常用的操作。
之前上文中介绍的都是值为空、只有键的情况,这可以称为是哈希表实现的“集合 Set”,而包含键值对的情况称为哈希表实现的“映射 Map”。

上文提到的哈希桶,就是指储存了键值对的一个位置。“哈希桶法”就是因为一个桶下面连着挂着好几个桶而得名的。
C++中的set与map
现在终于到了追本溯源的时候了。C++的STL库中,分别有着用红黑树实现的<set><map>,还有着用哈希表实现的<unordered_set><unordered_map>,这两种结构下最显著的区别就是其有序性了,红黑树默认是升序排列的。
上次讲到红黑树的查找删除操作时间复杂度都是O(logn),而哈希表是O(1)(平均复杂度,最坏情况O(n),持续哈希冲突),可以说是这种结构最大的优势了,但其需要预分派桶数组,拉链法还有存新链表,造成更多的空间占用。那么<unordered_set>和<unordered_map>大多会用在不关心顺序,追求快速操作的场景,其他情况都用<set><map>即可。
除了STL容器的通用方法以外,集合和映射还有这些用法。
//集合
set<int> s1 = { 1, 3, 2 };
unordered_set<int> s2 = { 1, 3, 2 };
s1.count(1);//在set中由于不重复性,可用于检测存在否
s2.count(1);//返回0或1
//对于有序的set
cout << *s1.lower_bound(1) << endl;//找到大于等于目标值的数迭代器
cout << *s1.upper_bound(1) << endl;//找到大于目标值的数迭代器
//对于无序的unordered_set
int num = s2.bucket_count();//桶的数量
cout << num << endl;
cout << s2.load_factor() << endl;//查看负载因子
s2.rehash(11);//设置桶的数量,重哈希,这个过程也包含对照负载因子扩容
num = s2.bucket_count();
cout << num << endl;
//映射
map<int, int> m1 = { {1, 3}, {2, 9}, {3, 4} };//前为key后为value
unordered_map<int, int> m2 = { {1, 3}, {2, 9}, {3, 4} };
m1.count(1);//检测存在否
m2.count(1);
//插入键值对,若键已存在则不覆盖
m1.emplace(2, 1);
m2.emplace(2, 1);
m1.insert({ 4, 6 });//这个返回迭代器
m2.insert({ 4, 6 });
//通过[key]访问value
cout << m1[1] << endl;
cout << m2[4] << endl;
//对于有序的map //用first和second访问key和value
cout << m1.lower_bound(1)->first << endl;//找到key大于等于目标值的数迭代器
cout << m1.upper_bound(1)->second << endl;//找到key大于目标值的数迭代器
//对于无序的unordered_map
cout << m2.bucket(3) << endl;//返回key3的桶编号
m2.reserve(10);//预分配空间
正好,一道名为“数组的度”的题就是用哈希表解决的,就在这里练练手吧!

int findShortestSubArray(vector<int>& nums) {//key用来记录对应的数,vector用来记录索引unordered_map<int, vector<int>> m; //第一次记录for(int i = 0; i < nums.size(); i++){if(!m.count(nums[i])){ //分别是 出现次数、头索引、尾索引m[nums[i]] = {1, i, i};}else{ //增加次数,更新尾索引m[nums[i]][0]++;m[nums[i]][2] = i;}}//寻找出现次数最大的int num = 0, minLength = 0;//注意,获取的每一个是键值对类型pair<T1, T2>for(pair<int, vector<int>> it : m){if(num < it.second[0]){ num = it.second[0]; minLength = it.second[2] - it.second[1] + 1; }else if(num == it.second[0]){ if(minLength > it.second[2] - it.second[1] + 1){ minLength = it.second[2] - it.second[1] + 1;}}}return minLength;}
小结
最近笔者还真抽不出时间好好学习游戏开发有关的知识,七七八八的事情挺多。不过瓜熟蒂落,水到渠成,把事情都梳理顺畅,再着手沉淀也不晚。

如有补充纠正欢迎留言。
相关文章:
数据结构:哈希表 | C++中的set与map
上回说到,红黑树是提升了动态数据集中频繁插入或删除操作的性能。而哈希表(Hash Table),则是解决了传统数组或链表查找数据必须要遍历的缺点。 哈希表 哈希表的特点就是能够让数据通过哈希函数存到表中,哈希函数能够将数据处理为表中位置的索…...
随笔 20250413 Elasticsearch 的 term 查询
你这个问题非常经典,来自于 Elasticsearch 的 term 查询是 ✅精确匹配(case-sensitive,大小写敏感)! 🧨 为什么查不到 "World"? 你的查询语句是: GET /movie/_search {&…...
容器初始化Spring Boot项目原理,即web项目(war)包涉及相关类对比详解
以下是关于 SpringBootServletInitializer、ServletContainerInitializer、SpringServletContainerInitializer、WebApplicationInitializer 和 ServletInitializer 的对比详解及总结表格: 1. 核心对比详解 (1) SpringBootServletInitializer 作用: S…...
Python创意:AI图像生成
1. 基本概念 AI 图像生成通常基于以下几种方法: 一.生成对抗网络 (GAN) 生成对抗网络(GAN,Generative Adversarial Network)是一种深度学习框架,主要用于生成新的、类似于训练数据的样本。自2014年由Ian Goodfellow及…...
[ctfshow web入门] web29
前置知识 eval: 把字符串按照 PHP 代码来执行,例如eval(“echo 1;”);这个函数拥有回显 system:使php程序执行系统命令,例如,system(“ls”);就是查看当前目录,这个拥有回显 preg_match:查找字符串是否匹配…...
5.JVM-G1垃圾回收器
一、什么是G1 二、G1的三种垃圾回收方式 region默认2048 三、YGC的过程(Step1) 3.1相关代码 public class YGC1 {/*-Xmx128M -XX:UseG1GC -XX:PrintGCTimeStamps -XX:PrintGCDetails -XX:UnlockExperimentalVMOptions -XX:G1LogLevelfinest128m5% 60%6.4M 75M*/private stati…...
Odrive0.5.1-FOC电机控制 arm_cos_f32.cpp arm_sin_f32.cpp代码实现(一)
01 查表法 在 our_arm_cos_f32 函数中,查表(Look-Up Table, LUT) 的核心是 预计算的正弦值表 sinTable_f32,通过巧妙利用余弦与正弦的相位关系实现快速余弦计算。以下是详细解析: 1. 查的是什么表? (1) 表内…...
机械臂只有位置信息是否可以进行手眼标定?
平常我在做手眼标定时,一般都是通过OpenCV的cv::calibrateHandEye函数进行求解,需要输入多组不同的机械臂位姿。今天遇到了一款舵机机器人,只能获取位置,得不到姿态信息,想着那就把姿态都设为0,结果求不出来…...
Python 数据分析01 环境搭建教程
Python 数据分析01 环境搭建教程 一、安装 Python 环境 访问 Python 官方网站 Python 官网,选择适合你操作系统的 Python 版本进行下载。下载完成后,运行安装程序。在安装过程中,建议选择“Add Python to PATH”选项,这样可以在…...
使用 Visual Studio 2022 (VS2022) 编译 FreeCAD 1.0.0 的详细教程
一、环境准备 官方教程:在 Windows 上编译 - FreeCAD Documentation Windows 10/11(推荐) git vs2022 cmake 3.26.4 Doxygen1.12 二、获取源码与依赖 版本关系 打开Git Bash或CMD,执行以下命令 git clone --recurse-sub…...
Java高性能并发利器-VarHandle
1. 什么是 VarHandle? VarHandle 是 Java 9 引入的类,用于对变量(对象字段、数组元素、静态变量等)进行低级别、高性能的原子操作(如 CAS、原子读写)。它是 java.util.concurrent.atomic 和 sun.misc.…...
蓝桥杯单片机频率
long int Freq; unsigned int Timer_1000Ms; 加上 TMOD | 0x05; void Timer0Init(void) //0毫秒12.000MHz {AUXR & 0x7F; //定时器时钟12T模式TMOD & 0xF0; //设置定时器模式TMOD | 0x05;TL0 0x00; //设置定时初值TH0 0x00; //设置定时初值TF0 0; //清除TF0标…...
【Qt】【第三方库】spdlog日志模块的使用
版本 spdlog版本:1.5.0 采用1.5.0版本主要基于以下考虑:兼容Qt5.9.X版本和兼容C11。 spdlog 1.5.0下载地址:https://github.com/gabime/spdlog/releases/tag/v1.5.0 摘要 在Qt应用程序开发中,良好的日志系统至关重要。本文将介…...
elementui table禁用全选,一次限制勾选一项。
1、设置属性:selection-change“handleSelectionChange” <el-table:data"taskList"ref"tableDataRefs"selection-change"handleSelectionChange":header-cell-class-name"hideAllCheckbox">function handleSelecti…...
3.1多状态专题:LeetCode面试题17.16 按摩师
动态规划解决按摩师预约问题——以LeetCode面试题17.16为例 1.题目链接 LeetCode面试题17.16 按摩师 2.题目描述 一个有名的按摩师收到一系列的预约请求,每个预约都可以选择接受或不接受。但相邻的预约不能同时接受。给定一个包含各预约时长的数组 nums…...
遵循IEC 62304:构建安全可靠的医疗器械软件
目录 一、IEC 62304 标准概述 1. 标准定位与适用范围 二、核心内容与要求 1. 软件安全等级(Software Safety Classification) (1)分级标准 (2)分级依据 (3)验证要求 2. 软件…...
互联网三高-数据库高并发之分库分表
1 数据库概述 1.1 数据库本身的瓶颈 ① 连接数 MySQL默认最大连接数为100,允许的最大连接数为16384 ② 单表海量数据查询性能 单表最好500w左右,最大警戒线800w ③ 单数据库并发压力问题 MySQL QPS:1500左右/秒 ④ 系统磁盘IO、CPU瓶颈 1.2 数…...
UE5 在UE中创建骨骼动画
文章目录 创建动画的三种方式修改骨骼动画 创建动画的三种方式 方法一 打开一个已有的动画,左上角“创建资产/创建动画/参考姿势” 这将创建一个默认的A字形的骨骼,不建议这么做 方法二 打开一个已有的动画,左上角“创建资产/创建动画/当前…...
Day-01 前端 Web - HTMLCSS
目录 一、HTML 基础 1. HTML 简介 2. HTML 基本结构 3. 常用 HTML 标签 二、CSS 基础 1. CSS 简介 2. CSS 引入方式 3. 常用 CSS 选择器 4. 常用 CSS 属性 一、HTML 基础 1. HTML 简介 HTML(HyperText Markup Language)即超文本标记语言&…...
AWS出海合规解决方案:全球业务扩张的技术指南
1. 引言 随着企业加速全球化进程,出海业务面临的合规挑战日益复杂。AWS作为全球领先的云服务提供商,为企业提供了强大的工具和服务,以帮助它们满足各国的合规要求。本文将探讨如何利用AWS服务构建全面的出海合规解决方案。 2. 全球数据合规挑战 在开始讨论具体解决方案之…...
[ctfshow web入门] web38
信息收集 过滤多了php和file if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/flag|php|file/i", $c)){include($c);echo $flag;}}else{highlight_file(__FILE__); }解题 更多解法参考 [ctfshow web入门] web37 我们选个最简单的。但是因为php被过滤了我们改用…...
汽车CAN总线采样点和采样率详解
写在前面 本篇文章主要讲解在汽车电子中CAN总线采样率的相关知识点,内容涉及CAN波特率、采样点、时间份额、同步跳转宽度以及采样率的计算。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 1、CAN波特率 CAN波特率常规分为250kbps和500kbps,本文章主要以这两个波特率为…...
网络协议学习
最近在适配ESP32的网络驱动,借此机会先学习一下网络通信协议。 以太网帧、IP包及TCP与UDP的报文格式一文读懂网络报问中的检验和(checksum)—— 原理举例代码 提问腾讯元宝提示词: TCP窗口是干什么的拥塞窗口是什么的...
仙剑奇侠传98柔情版游戏秘籍
战斗秘技:在战斗中输入 “cheat”,然后输入 “v” 直接取胜;输入 “y” 敌人不攻击。另外,在战斗中按 “XJPXZ123” 加 “shift” 键,攻击力增加 1000%。等级提升秘籍:当李逍遥等级到达 99 级时…...
Maven error:Could not transfer artifact
问题描述 当项目从私有仓库下载依赖时,Maven 报错,无法从远程仓库下载指定的依赖包,错误信息如下: Could not transfer artifact com.ding.abcd:zabk-java:pom from/to releases (http://192.1122.101/repory/mavenleases/): 此…...
pytorch 反向传播
文章目录 概念计算图自动求导的两种模式 自动求导-代码标量的反向传播非标量变量的反向传播将某些计算移动到计算图之外 概念 核心:链式法则 深度学习框架通过自动计算导数(自动微分)来加快求导。 实践中,根据涉及号的模型,系统会构建一个计…...
WindowsPE文件格式入门06.手写最小PE
https://bpsend.net/thread-346-1-1.html 实现目标 实现目标:手写实现不大于 200 Byte大小的PE文件(又名:畸形PE/变形PE),要求MessageBox弹框显示一个字符串。实现要点:充分利用空间,在保证遵…...
并发编程--互斥锁与读写锁
并发编程–互斥锁与读写锁 文章目录 并发编程--互斥锁与读写锁1. 基本概念2. 互斥锁2.1 基本逻辑2.2 函数接口2.3示例代码12.4示例代码2 3. 读写锁3.1 基本逻辑3.2示例代码 1. 基本概念 互斥与同步是最基本的逻辑概念: 互斥指的是控制两个进度使之互相排斥&#x…...
记录第一次使用H5的WebBluetooth完成蓝牙标签打印机的(踩坑)过程
第1步 首先第一步,调试环境必须是https的,由于浏览器的强制安全策略,本地可以采用localhost 第2步 然后,如果打印需要服务UUID(Service UUID) 和 特征UUID(Characteristic UUID)&…...
2025 年“认证杯”数学中国数学建模网络挑战赛 A题 小行星轨迹预测
近地小行星( Near Earth Asteroids, NEAs )是轨道相对接近地球的小行 星,它的正式定义为椭圆轨道的近日距不大于 1.3 天文单位( AU )的小行星。 其中轨道与地球轨道最近距离小于 0.05A 且直径大于 140 米的小行星被…...
