19.哈希表的实现

server/2025/3/27 5:40:59/

1.哈希的概念

哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进⾏快速查找。

1.2.直接定址法

当关键字的范围⽐较集中时,直接定址法就是⾮常简单⾼效的⽅法,⽐如⼀组关键字都在[0,99]之间,那么我们开⼀个100个数的数组,每个关键字的值直接就是存储位置的下标。再⽐如⼀组关键字值都在[a,z]的⼩写字⺟,那么我们开⼀个26个数的数组,每个关键字acsii码-a ascii码就是存储位置的下标。也就是说直接定址法本质就是⽤关键字计算出⼀个绝对位置或者相对位置

1.3.哈希冲突 

直接定址法的缺点也⾮常明显,当关键字的范围⽐较分散时,就很浪费内存甚⾄内存不够⽤。

这⾥存在的⼀个问题就是,两个不同的key可能会映射到同⼀个位置去,这种问题我们叫做哈希冲突。

1.4.负载因子

假设哈希表中已经映射存储了N个值,哈希表的大小为M,那么 负载因子 = N/M ,负载因⼦有些地⽅也翻译为载荷因⼦/装载因⼦等,他的英⽂为load factor。负载因⼦越⼤,哈希冲突的概率越⾼,空间利⽤率越⾼;负载因⼦越⼩,哈希冲突的概率越低,空间利⽤率越低。

1.5.将关键字转为整数

我们将关键字映射到数组中位置,⼀般是整数好做映射计算,如果不是整数,我们要想办法转换成整数。后面给具体实现方法。

2.哈希函数

⼀个好的哈希函数应该让N个关键字被等概率的均匀的散列分布到哈希表的M个空间中,但是实际中却很难做到,但是我们要尽量往这个⽅向去考量设计。

2.1除法散列法

假设哈希表的⼤⼩为M,那么通过key除以M的余数作为映射位置的下标,也就是哈希函数为:h(key) = key % M。

当使⽤除法散列法时,要尽量避免M为某些值,如2的幂,10的幂等。如果是2^x ,那么key %

2^x本质相当于保留key的后X位,那么后x位相同的值,计算出的哈希值都是⼀样的,就冲突了。如: {63 , 31}看起来没有关联的值,如果M是16,也就是2^4 ,那么计算出的哈希值都是15,因为63的⼆ 进制后8位是 00111111,31的⼆进制后8位是 00011111。如果是10^2 ,就更明显了,保留的都是10进值的后x位,如:{112, 12312},如果M是100,也就是10^2 ,那么计算出的哈希值都是12。

当使⽤除法散列法时,建议M取不太接近2的整数次幂的⼀个质数(素数)。

3.处理哈希冲突

实践中哈希表⼀般还是选择除法散列法作为哈希函数,当然哈希表⽆论选择什么哈希函数也避免不了冲突,那么插⼊数据时,如何解决冲突呢?主要有两种两种⽅法,开放定址法和链地址法。

3.1开放定址法

在开放定址法中所有的元素都放到哈希表⾥,当⼀个关键字key⽤哈希函数计算出的位置冲突了,则按照某种规则找到⼀个没有存储数据的位置进⾏存储,开放定址法中负载因⼦⼀定是⼩于1的。
1.线性探测:
1.1 从发⽣冲突的位置开始,依次线性向后探测,直到寻找到下⼀个没有存储数据的位置为⽌,如果⾛
到哈希表尾,则回绕到哈希表头的位置。1.2 h(key) = hash0 = key % M,, hash0位置冲突了,则线性探测公式为:
hc(key,i) = hashi = (hash0 + i) % M, i = {1, 2, 3, ..., M − 1},
因为负载因⼦⼩于1,则最多探测M-1次,⼀定能找到⼀个存储key的位置。2.⼆次探测:
2.1 从发⽣冲突的位置开始,依次左右按⼆次⽅跳跃式探测,直到寻找到下⼀个没有存储数据的位置为
⽌,如果往右⾛到哈希表尾,则回绕到哈希表头的位置;如果往左⾛到哈希表头,则回绕到哈希表
尾的位置;
2.2 h(key) = hash0 = key % M , hash0位置冲突了,则⼆次探测公式为:
hc(key,i) = hashi = (hash0 ± i^2 ) % M, i = {1, 2, 3, ..., M/2}
2.3 ⼆次探测当 hashi = (hash0 − i^2)%M 时,当hashi<0时,需要hashi += M

3.2扩容:

这⾥哈希表负载因⼦控制在0.7,当负载因⼦到0.7以后我们就需要扩容了,我们还是按照2倍扩容,但是同时我们要保持哈希表⼤⼩是⼀个质数,第⼀个是质数,2倍后就不是质数了。那么如何解决了,⼀种⽅案就是除法散列中Java HashMap的使⽤2的整数幂,但是计算时不能直接取模的改进⽅法。另外⼀种⽅案是sgi版本的哈希表使⽤的⽅法,给了⼀个近似2倍的质数表,每次去质数表获取扩容后的⼤⼩。

3.3key不能取模的问题

当key是string/自定义等类型时,key不能取模, 那么我们需要给HashTable增加⼀个仿函数,这个仿函 数⽀持把key转换成⼀个可以取模的整形,如果key可以转换为整形并且不容易冲突,那么这个仿函数 就⽤默认参数即可,如果这个Key不能转换为整形,我们就需要⾃⼰实现⼀个仿函数传给这个参数,实 现这个仿函数的要求就是尽量key的每值都参与到计算中,让不同的key转换出的整形值不同。string 做哈希表的key⾮常常⻅,所以我们可以考虑把string特化⼀下。

3.4开放定址法代码实现

*3.4链地址法

哈希表中存储⼀个指针,没有数据映射这个位置时,这个指针为空,有多个数据映射到这个位置时,我们把这些冲突的数据链接成⼀个链表,挂在哈希表这个位置下⾯,链地址法也叫做拉链法或者哈希桶。

扩容:

开放定址法负载因⼦必须⼩于1,链地址法的负载因⼦就没有限制了,可以⼤于1。负载因⼦越⼤,哈希冲突的概率越⾼,空间利⽤率越⾼;负载因⼦越⼩,哈希冲突的概率越低,空间利⽤率越低;stl中unordered_xxx的最⼤负载因⼦基本控制在1,⼤于1就扩容。
极端场景:
如果极端场景下,某个桶特别⻓怎么办?这是把链表转换成红黑树,提供一个思路。

3.5链地址法代码实现

文章来源:https://blog.csdn.net/2401_86931059/article/details/146359276
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/server/179046.html

相关文章

人工智能之数学基础:特征值和特征向量

本文重点 在线性代数中,我们经常使用到的一个概念就是特征值和特征向量,在机器学习中,尤其是图像领域,这个概念尤为的重要,一个矩阵可以对向量进行加工,从而将一个向量变成新的向量。有的时候,一个向量经过矩阵加工之后,新生成的向量与原来的向量共线(方向可能相反)…

【2025】基于python+flask的篮球交流社区平台设计与实现(源码、万字文档、图文修改、调试答疑)

基于 PythonFlask 的篮球交流社区平台设计与实现 系统功能结构图如下&#xff1a; 一、课题背景 篮球作为一项广受欢迎的运动&#xff0c;拥有庞大的爱好者群体。随着互联网的发展&#xff0c;越来越多的篮球爱好者希望有一个在线平台&#xff0c;能够方便地获取篮球赛事信息、…

GitHub 上的 Khoj 项目:打造你的专属 AI 第二大脑

在信息爆炸的时代&#xff0c;高效管理和利用个人知识变得愈发重要。GitHub 上的 Khoj 项目为我们提供了一个强大的解决方案&#xff0c;它能成为你的 “AI 第二大脑”&#xff0c;帮你轻松整合、搜索和运用知识。今天&#xff0c;就来详细了解下 Khoj。​ Khoj 是什么&#x…

《BUG生存指南》(有芝士的小说)

《BUG生存指南》 “叮咚&#xff01;” 小张的手机响了&#xff0c;他抬头看了一眼&#xff0c;是一条来自“程序员自救互助群”的消息&#xff1a; 【紧急通知&#xff1a;今晚午夜12点&#xff0c;所有未解决的BUG将实体化&#xff0c;威胁程序员安全。请及时修复代码&#…

什么是跳表?(Skip List)

跳表&#xff08;Skip List&#xff09;完整讲解 跳表是一种基于链表的有序数据结构&#xff0c;通过多层索引提高查找速度。它的核心思想是&#xff1a;“用多个层级的索引来加速查找”&#xff0c;从而达到类似二分查找的效果&#xff0c;同时保留链表的动态性。 1. 跳表的基…

C语言代码如何操作硬件?

在嵌入式开发中&#xff0c;C代码通过直接操作硬件寄存器来控制硬件&#xff0c;这些寄存器被映射到特定的内存地址。以下是其工作原理的详细分步解释&#xff1a; 1. 内存映射硬件寄存器 微控制器将外设&#xff08;如GPIO、定时器、UART等&#xff09;的寄存器映射到内存地…

基于SpringBoot的名著阅读网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

解锁云原生后端开发新姿势:腾讯云大模型API深度整合实战

在云原生与AI技术深度融合的今天&#xff0c;如何将大模型能力无缝嵌入后端架构&#xff0c;已成为开发者构建下一代智能应用的核心命题。本文将深入解析腾讯云大模型API&#xff08;如DeepSeek-R1/V3、混元大模型&#xff09;与云原生技术的创新结合方案&#xff0c;通过架构设…