从零带你底层实现unordered_map (2)
💯 博客内容:从零带你实现unordered_map
😀 作 者:陈大大陈
🚀 个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!
💖 欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信 😘
目录
闭散列/哈希桶 拉链法
开散列图示:
开散列代码:
增容代码:
哈希/散列:映射,关键字和另一个值建立一个关联关系。
哈希表/散列表:映射,关键字和储存位置建立一个关联关系。
哈希/散列是一种算法思想,而哈希表/散列表是基于这种算法思想而实现的一种数据结构,这点很容易混淆。
上一篇博客介绍了两个解决哈希冲突的方法,
1.线性探测 hashi+i (i>=0)
2.二次探测 hashi+i^2 (i>=0)
这两种方法都不算是什么灵丹妙药,还是太慢。
最好的方法是下面这个。
闭散列/哈希桶 拉链法
哈希每一个存的不是唯一的值,而是一个指针数组。
这样一来,key值相同的值都会存到一个指针数组里面,查找就方便了很多。
它的查找直接‘’内部消化‘’,不会影响到别的值。
这样的每一个节点,我们称之为桶。
当一个桶的节点过多时吗,这个桶的存储结构由链表变为红黑树。
平均时间复杂度是O(1)。
当存储的值是string等类型的话,不能直接入表。
要使用仿函数来类型转换。
HashFunc的作用是转成整型值。
直接把字母的ASCII值加起来看行不行。
需要特别注意的是,汉字的ASCII值是负数,存储的时候需要用到特殊的方法。
否则会发生整形提升,简单的两个汉字加起来就能有好几亿。
上篇文章也说过了:
解决哈希冲突 两种常见的方法是:闭散列和开散列
闭散列,也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有
空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。
今天咱们就来提提开散列。
开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。
开散列图示:

开散列代码:
#define _CRT_SECURE_NO_WARNINGS
template<class V>
struct HashBucketNode
{HashBucketNode(const V& data): _pNext(nullptr), _data(data){}HashBucketNode<V>* _pNext;V _data;
};
template<class V>
class HashBucket
{typedef HashBucketNode<V> Node;typedef Node* PNode;
public:HashBucket(size_t capacity = 3) : _size(0){_ht.resize(GetNextPrime(capacity), nullptr);}// 哈希桶中的元素不能重复PNode* Insert(const V& data){// 确认是否需要扩容。。。// _CheckCapacity();// 1. 计算元素所在的桶号size_t bucketNo = HashFunc(data);// 2. 检测该元素是否在桶中PNode pCur = _ht[bucketNo];while (pCur){if (pCur->_data == data)return pCur;pCur = pCur->_pNext;}// 3. 插入新元素pCur = new Node(data);pCur->_pNext = _ht[bucketNo];_ht[bucketNo] = pCur;_size++;return pCur;}// 删除哈希桶中为data的元素(data不会重复),返回删除元素的下一个节点PNode* Erase(const V& data){size_t bucketNo = HashFunc(data);PNode pCur = _ht[bucketNo];PNode pPrev = nullptr, pRet = nullptr;while (pCur){if (pCur->_data == data){if (pCur == _ht[bucketNo])_ht[bucketNo] = pCur->_pNext;elsepPrev->_pNext = pCur->_pNext;pRet = pCur->_pNext;delete pCur;_size--;return pRet;}}return nullptr;}PNode* Find(const V& data);size_t Size()const;bool Empty()const;void Clear();bool BucketCount()const;void Swap(HashBucket<V, HF>& ht;~HashBucket();
private:size_t HashFunc(const V& data){return data % _ht.capacity();}
private:vector<PNode*> _ht;size_t _size; //哈希表中有效元素的个数
};
桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可
能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希
表进行增容,那该条件怎么确认呢?开散列最好的情况是:每个哈希桶中刚好挂一个节点,
再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,可
以给哈希表增容。
增容代码:
void _CheckCapacity()
{size_t bucketCount = BucketCount();if(_size == bucketCount){HashBucket<V, HF> newHt(bucketCount);for(size_t bucketIdx = 0; bucketIdx < bucketCount; ++bucketIdx){PNode pCur = _ht[bucketIdx];while(pCur){// 将该节点从原哈希表中拆出来_ht[bucketIdx] = pCur->_pNext;// 将该节点插入到新哈希表中size_t bucketNo = newHt.HashFunc(pCur->_data);pCur->_pNext = newHt._ht[bucketNo];newHt._ht[bucketNo] = pCur;pCur = _ht[bucketIdx];}}newHt._size = _size;this->Swap(newHt);}
}
这块东西实在是太多,下篇博客咱们继续实现。
相关文章:

从零带你底层实现unordered_map (2)
💯 博客内容:从零带你实现unordered_map 😀 作 者:陈大大陈 🚀 个人简介:一个正在努力学技术的准C后端工程师,专注基础和实战分享 ,欢迎私信! 💖 欢迎大家…...
打造企业AI数字人专属IP的重要性
在数字化时代,企业数字人专属IP的打造成为了企业品牌建设的重要组成部分。企业数字人专属IP是指是利用人工智能技术实现与真人直播形象的1:1克隆,即克隆出一个数字化的真人形象,作为独有的企业数字人形象,可以用于产品推广、品牌宣…...

docker容器的生命周期管理常用命令
容器的生命周期管理命令 docker create :创建一个新的容器但不启动它 docker create nginx docker run :创建一个新的容器并运行一个命令 常用选项: 常用选项1. --add-host:容器中hosts文件添加 host:ip 映射记录 2. -a, --attach&#…...
CF 1900B Laura and Operations 学习笔记
原题链接 传送门 题意 输入三个数字a,b,c表示1,2,3的数目,也就是说有a个1,b个2,c个3,每一次可以删除两个不同的数字,增加一个剩下的数字,比如说删除1和3,增加2&#x…...
Linux学习笔记6-串口应用
到现在为止都是在开发板上运行的裸机程序,相当于之前学习STM32单片机时走过的路,还没有真正进入到核心的驱动开发部分,但这都是基础,所以慢慢来不着急。 接下来进入串口通信的学习,和GPIO一样,也是和单片机…...
ubuntu下如何查看.gz压缩包中的内容,以及grep过滤查找文件中的某些内容
1、查看压缩包file.gz中的全部内容 $ zcat file.gz 2、对一个.gz的压缩包解压缩 $ gunzip file.gz 3、过滤查找文件中的某些内容 $ grep "Hello" file.txt 注:我通常先解压,然后再grep 4、过滤查找文件中的内容,并显示其上下3行…...

AI 重构工业制造的故事 我们从大模型开始讲起
在数字化浪潮的推动下,工业制造领域正经历着一场前所未有的变革。人工智能(AI)作为这场变革的关键推动者之一,正以惊人的速度颠覆传统制造业。而大模型作为AI时代最先进的科技工具之一,或将成为引领这场变革的利器&…...

easyExcel 注解开发 快速以及简单上手 以及包含工具类
easyExcel 简单快速使用 1. mevan 这里版本我这里选的是 poi 4.1.2和 ali的easyexcel 的 3.3.1。 因为阿里easy是根据poi的依赖开发的有关系,两者需要对应要不然就会有很多bug和错误在运行时发生。需要版本对应,然而就是easy的代码也会有bug这个版本是比…...

VS2010配置opencv2.4.10
1.下载opencv2.4.10,百度网盘链接如下: 链接:https://pan.baidu.com/s/1UdoQJbRUEB_G2urT703xYQ 提取码:7lbd 2.运行opencv-2.4.10.exe,将文件提取到一个自定义目录里: 3.添加系统环境变量 在“系统变量…...
Android:控制按键灯亮灭【button-backlight】
/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 1.导包 import java.io.DataOutputStream; import java.io.FileOutputStream; Handler mHandler3; 2.新建handler对象 public void init(Context context, IWindowManager windowMan…...

1、nmap常用命令
文章目录 1. 主机存活探测2. 常见端口扫描、服务版本探测、服务器版本识别3. 全端口(TCP/UDP)扫描4. 最详细的端口扫描5. 三种TCP扫描方式(1)TCP connect 扫描(2)TCP SYN扫描(3)TCP …...

Redis缓存设计典型问题
目录 缓存穿透 缓存失效(击穿) 缓存雪崩 热点缓存key重建优化 缓存与数据库双写不一致 缓存穿透 缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据…...

【python】python基础速通系列2-python程序中的积木块
【组成Python的几个单位】 变量:指向值的名称。或者说变量是一个名称,这个名称指向一个具体的指。比如n=17,就说这个叫做n的变量的值是17。表达式:是值,变量和运算符的组合。如果把变量理解为名词,那么表达式就是把名词连起来的动词形容词。比如:n+25。语句:代码的基本…...
本地开启https,配置nodeJs服务
服务端和客户端各有一对公钥和私钥,使用公钥加密的数据只能用私钥解密,建立https传输之前,客户端和服务端互换公钥。客户端发送数据前使用服务端公钥加密,服务端接收到数据后使用私钥解密,反之亦如此。 1. 公钥私钥的…...

项目中的svg图标的封装与使用
1.安装 npm install vite-plugin-svg-icons -D2.在vite.config.ts中配置 **所有的svg图标都必须放在assets/icons // 引入svg import { createSvgIconsPlugin } from vite-plugin-svg-iconsexport default defineConfig({plugins: [vue(),createSvgIconsPlugin({iconDirs: [p…...

文件服务器迁移
文件服务器迁移还是比较简单的 win server加域 导出配额文件 选中所有项,点击导出 导出共享文件夹权限列表 导出文件夹的权限表,留作备用。需要用到“icacls” icacls c:\windows\* /save aclfile /t # C:\Windows 目录及其子目录中所有文件的 DAC…...

虹科Pico汽车示波器 | 汽车免拆检修 | 2011款瑞麒M1车发动机起动困难、加速无力
一、故障现象 一辆2011款瑞麒M1车,搭载SQR317F发动机,累计行驶里程约为10.4万km。该车因发动机起动困难、抖动、动力不足、热机易熄火等故障进厂维修。用故障检测仪检测,发动机控制单元(ECU)中存储有故障代码“P0340相…...

深度学习之图像分类(十五)DINAT: Dilated Neighborhood Attention Transformer详解(一)
Dilated Neighborhood Attention Transformer Abstract Transformers 迅速成为跨模态、领域和任务中应用最广泛的深度学习架构之一。在视觉领域,除了对普通Transformer的持续努力外,分层Transformer也因其性能和易于集成到现有框架中而受到重视。这些模…...

和数集团出席中科院上海高研院第三十三期“高研交叉论坛”信息能源融合专场
2023年11月21日,中国科学院上海高等研究院第三十三期“高研交叉论坛”信息能源融合专场在上海高研院成功举办。本次论坛由中国科学院上海高等研究院智能信息通信技术研究与发展中心、中国科学院低碳转化科学与工程重点实验室、中科院和数智能区块链与能源系统应用联…...

GitHub----使用记录
一、上传文件到仓库 1、首先新建一个github仓库 然后先记住这一句指令 2、下载git工具 https://git-scm.com/downloads 下载工具安装不用运行 3、使用git工具上传文件并推送 找到你想上传的文件的位置,右击git Bush here git init :初始化这个仓…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...