当前位置: 首页 > news >正文

从零带你底层实现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)

&#x1f4af; 博客内容&#xff1a;从零带你实现unordered_map &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准C后端工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家…...

打造企业AI数字人专属IP的重要性

在数字化时代&#xff0c;企业数字人专属IP的打造成为了企业品牌建设的重要组成部分。企业数字人专属IP是指是利用人工智能技术实现与真人直播形象的1:1克隆&#xff0c;即克隆出一个数字化的真人形象&#xff0c;作为独有的企业数字人形象&#xff0c;可以用于产品推广、品牌宣…...

docker容器的生命周期管理常用命令

容器的生命周期管理命令 docker create &#xff1a;创建一个新的容器但不启动它 docker create nginx docker run :创建一个新的容器并运行一个命令 常用选项&#xff1a; 常用选项1. --add-host&#xff1a;容器中hosts文件添加 host:ip 映射记录 2. -a, --attach&#…...

CF 1900B Laura and Operations 学习笔记

原题链接 传送门 题意 输入三个数字a,b,c表示1&#xff0c;2&#xff0c;3的数目&#xff0c;也就是说有a个1&#xff0c;b个2&#xff0c;c个3&#xff0c;每一次可以删除两个不同的数字&#xff0c;增加一个剩下的数字&#xff0c;比如说删除1和3&#xff0c;增加2&#x…...

Linux学习笔记6-串口应用

到现在为止都是在开发板上运行的裸机程序&#xff0c;相当于之前学习STM32单片机时走过的路&#xff0c;还没有真正进入到核心的驱动开发部分&#xff0c;但这都是基础&#xff0c;所以慢慢来不着急。 接下来进入串口通信的学习&#xff0c;和GPIO一样&#xff0c;也是和单片机…...

ubuntu下如何查看.gz压缩包中的内容,以及grep过滤查找文件中的某些内容

1、查看压缩包file.gz中的全部内容 $ zcat file.gz 2、对一个.gz的压缩包解压缩 $ gunzip file.gz 3、过滤查找文件中的某些内容 $ grep "Hello" file.txt 注&#xff1a;我通常先解压&#xff0c;然后再grep 4、过滤查找文件中的内容&#xff0c;并显示其上下3行…...

AI 重构工业制造的故事 我们从大模型开始讲起

在数字化浪潮的推动下&#xff0c;工业制造领域正经历着一场前所未有的变革。人工智能&#xff08;AI&#xff09;作为这场变革的关键推动者之一&#xff0c;正以惊人的速度颠覆传统制造业。而大模型作为AI时代最先进的科技工具之一&#xff0c;或将成为引领这场变革的利器&…...

easyExcel 注解开发 快速以及简单上手 以及包含工具类

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

VS2010配置opencv2.4.10

1.下载opencv2.4.10&#xff0c;百度网盘链接如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1UdoQJbRUEB_G2urT703xYQ 提取码&#xff1a;7lbd 2.运行opencv-2.4.10.exe&#xff0c;将文件提取到一个自定义目录里&#xff1a; 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. 全端口&#xff08;TCP/UDP&#xff09;扫描4. 最详细的端口扫描5. 三种TCP扫描方式&#xff08;1&#xff09;TCP connect 扫描&#xff08;2&#xff09;TCP SYN扫描&#xff08;3&#xff09;TCP …...

Redis缓存设计典型问题

目录 缓存穿透 缓存失效&#xff08;击穿&#xff09; 缓存雪崩 热点缓存key重建优化 缓存与数据库双写不一致 缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c; 缓存层和存储层都不会命中&#xff0c; 通常出于容错的考虑&#xff0c; 如果从存储层查不到数据…...

【python】python基础速通系列2-python程序中的积木块

【组成Python的几个单位】 变量:指向值的名称。或者说变量是一个名称,这个名称指向一个具体的指。比如n=17,就说这个叫做n的变量的值是17。表达式:是值,变量和运算符的组合。如果把变量理解为名词,那么表达式就是把名词连起来的动词形容词。比如:n+25。语句:代码的基本…...

本地开启https,配置nodeJs服务

服务端和客户端各有一对公钥和私钥&#xff0c;使用公钥加密的数据只能用私钥解密&#xff0c;建立https传输之前&#xff0c;客户端和服务端互换公钥。客户端发送数据前使用服务端公钥加密&#xff0c;服务端接收到数据后使用私钥解密&#xff0c;反之亦如此。 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加域 导出配额文件 选中所有项&#xff0c;点击导出 导出共享文件夹权限列表 导出文件夹的权限表&#xff0c;留作备用。需要用到“icacls” icacls c:\windows\* /save aclfile /t # C:\Windows 目录及其子目录中所有文件的 DAC…...

虹科Pico汽车示波器 | 汽车免拆检修 | 2011款瑞麒M1车发动机起动困难、加速无力

一、故障现象 一辆2011款瑞麒M1车&#xff0c;搭载SQR317F发动机&#xff0c;累计行驶里程约为10.4万km。该车因发动机起动困难、抖动、动力不足、热机易熄火等故障进厂维修。用故障检测仪检测&#xff0c;发动机控制单元&#xff08;ECU&#xff09;中存储有故障代码“P0340相…...

深度学习之图像分类(十五)DINAT: Dilated Neighborhood Attention Transformer详解(一)

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

和数集团出席中科院上海高研院​第三十三期“高研交叉论坛”信息能源融合专场

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

GitHub----使用记录

一、上传文件到仓库 1、首先新建一个github仓库 然后先记住这一句指令 2、下载git工具 https://git-scm.com/downloads 下载工具安装不用运行 3、使用git工具上传文件并推送 找到你想上传的文件的位置&#xff0c;右击git Bush here git init &#xff1a;初始化这个仓…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...