哈希表、哈希冲突解决办法

文章目录

    • 一、什么是哈希表?
    • 二、什么是哈希冲突?怎样解决?
    • 三、哈希表的大小为什么是质数?
    • 四、链表法
    • 五、开放地址法
      • 线性探测法
      • 平方探测法
      • 双哈希(Double Hashing)
    • 六、哈希表满了怎么办?
    • 七、完美哈希
    • 八、一些使用哈希解决的算法题

在我以往的认知中,哈希就是进行唯一映射,指定一个关键字,就能映射唯一的值。平时经常使用linux下的 md5sum命令用来比较两个文件是否相同。至于如何哈希原理,它们是怎样进行唯一映射的,一直没有去梳理,如今该填的洞还是得补上。

一、什么是哈希表?

我们知道,普通数组能够直接寻址,在O(1)时间内能访问到数组中的任意位置。它需要足够大的空间,为每一个关键字保留一个位置。当关键字取值的范围很大,储存空间又有限时,能不能同样用数组的形式实现O(1)查找?

哈希表(Hash Table)就是这样的数据结构,当实际储存的关键字集合,比所有可能的关键字的全集小许多时,使用一个长度有限的数组去储存这些关键字,从而节省大量的空闲空间。它也被称作为散列表,因为它的键是分散存储在数组中的。

如图,黄色区域为键的全集,范围为0~99,绿色区域为实际存储的键。直接寻址需要为所有的键开辟空间,而哈希映射仅需为需要储存的键分配空间,储存空间比直接寻址少得多。

在这里插入图片描述

哈希表的核心思想是将键转换为数组的索引位置,以便快速查找对应的值。它使用哈希函数将键映射到数组的索引位置,这个索引位置称为哈希值。哈希映射是唯一映射,一个键永远只能产生一个哈希值,这种映射关系,就是我们所说的哈希函数。常见的哈希函数包括MD5、SHA-1、SHA-256等。

二、什么是哈希冲突?怎样解决?

通过取某运算,保持了哈希表中查找一个元素只要O(1)时间的优势。但细心的朋友会发现,上图中当键为7,17时,两个键会映射到同一个哈希值。我们称这种情形为哈希冲突,由于哈希函数不够“随机”,不同的键通过哈希函数计算得到相同的哈希值。

有人会说,简单,将哈希表增大,某上一个更大的值函数不就行了吗?可是可以,但哈希的精髓在于尽可能的节省空间与查找时间。最普通的哈希表,就是一个直接寻址的数组。不过,还有其它更高效的方法解决哈希冲突,如链表法,开放地址法等,这个后面再讲。

当哈希表中存储的键越来越多时,冲突的概率会不断增大,总会有哈希表再也装不下键的时候。所以,合理的控制一个哈希表的大小也极为重要。通常,将哈希表的大小设置为一个质数,是需要储存的键的数量的两倍。

三、哈希表的大小为什么是质数?

当哈希表的大小选择为一个合数(非质数)时,键的哈希值可能与哈希表的大小存在公因子。这种情况下,多个键的哈希值可能会映射到相同的索引位置,导致哈希冲突的概率增加。

让我们通过一个例子来说明这个问题。假设我们有一个哈希表大小为10,键的哈希函数将键映射到0到9的索引位置。我们有两个键:15和25。它们的哈希值分别为5和5。由于它们的哈希值都映射到相同的索引位置5,发生了哈希冲突。

倘若我们选择一个质数作为哈希表的大小,比如13,再次计算这两个键的哈希值。键15的哈希值为2,键25的哈希值为12。由于13是质数,与13存在公因子的数字较少,因此键的哈希值在13以内相同的概率会少很多。

通过选择质数作为哈希表的大小,可以减少键的哈希值与哈希表大小之间存在公因子的情况,从而减少哈希冲突的概率。这样可以更均匀地分布键值对,提高哈希表的性能和效率。

四、链表法

链表法其实很简单,就是将映射到同一地址的元素都放在一个链表中。哈希表中每个槽都有一个指针,指向所有映射到同一位置的元素链表表头,如果当前槽位没有这样的元素,头指针为空。

在这里插入图片描述

采用双向链表结构是为了删除与插入操作都能控制时间在O(1)范围内。每一个槽位链表的长度就是它的负载因子。通过上述结构不难看出,查找需要遍历链表,查找的时间取决于链表的长度。并且,当散列不均匀时,某一些链过长,有一些链很短,查找的效率也是不稳定的。

所以,一个好的哈希函数不应该将太多的输入映射到相同的输出。

五、开放地址法

除了链表法解决哈希冲突外,还可以通过开放地址的方式来解决哈希冲突。之所以叫开放地址,是因为它们都是通过将冲突的键,存放到哈希表空闲的其它地址中去,将未使用的地址开放出来,直到表空间耗尽。开方地址有多种方法,下面一一介绍。

线性探测法

探测(Probe),是指当地址冲突后,会继续去寻找表中可用的地址。线性探测,则是顺着当前位置向后查找。

如图,将关键字以线性探测的方式插入到哈希表中,哈希表的长度为13。

在这里插入图片描述

不难看出,线性探测随着填充因子的增加,冲突会聚集在一起,形成聚集效应。负载因子需要控制在70%左右,否则冲突次数飙升。数据分布本身不均匀也会导致冲突分布不均匀。线性探测法实现简单,但随着负载增加,性能下降明显。

平方探测法

如果遇到冲突,就往(原始位置 + i2)的位置寻找空位,i为查找次数。

如图:

在这里插入图片描述

平方探测法是解决哈希冲突的一种开放地址法。当发生哈希冲突时,它按一定的平方序列探测下一个位置。

优点:

  1. 降低了聚集效应。冲突分配更加均匀。
  2. 减少了聚簇内的查找时间。
  3. 可以提高负载因子。平均查找长度较短。

缺点:

  1. 需要计算平方序列值,实现较为复杂。
  2. 当Step超过表大小时计算会溢出。
  3. 随机性较差,数据分布不均会影响性能。
  4. 二次方探测发生冲突的概率较大。
  5. 删除操作会产生空洞,需要惰性删除避免影响。

总体而言,平方探测法通过牺牲部分实现复杂度和冲突计算时间来减轻聚集效应,在较高负载下性能较好。仍需要考虑非全域性问题。

什么是惰性删除?

惰性删除(Lazy deletion) 是一种常用的哈希表优化方法,主要应用于开放定址法中的删除操作。其基本思路是:

  1. 当删除键值对时,先将其标记为"已删除",而不直接从散列表中删除记录。
  2. 对后续插入操作,会扫描标记的已删除槽位并进行插入。
  3. 直到被后续插入覆盖,标记的删除状态才真正删除。

优点是可以避免删除后产生的空槽位,保证使用空间的连续性,减少冲突次数,提高效率。

缺点是需要扫描已删除槽位,增加查询的开销。

主要应用在平方探测法、线性探测法等开放定址中的删除操作,使得开放定址法的执行效率大为提升。是哈希表优化的重要手段之一。也可视作是一种延迟紧缩、空间换时间的实现。

双哈希(Double Hashing)

除了第一个哈希函数外,还有一个哈希函数用于解决冲突。

如果遇到冲突,新位置 = 原始位置 + i * hash2(key),i为查找次数。

hash2(key) = R - (key % R)
R要取比数组尺寸小的质数。
例如,哈希表长度为13,R = 7,hash2(key) = 7 - (key % 7)
也就是说,第二次哈希结果在1-7之间,不会等于0。

举例:
在这里插入图片描述

双哈希法的主要优点:

  1. 采用双重散列,冲突分布更加均匀。
  2. 相比线性探测,可以有效减少聚集问题。
  3. 指数增长级别更低,平均查找长度较短。
  4. 算法和实现都比较简单。
  5. 允许删除而不产生过多空槽。

双哈希法通过两次散列的思想,改进了性能和冲突分布,是一种效率较好的开方地址方法。

六、哈希表满了怎么办?

再哈希(rehash)

  • 当哈希表的插槽被占用了70%后,查找效率会严重下降,需要对哈希表进行扩展。

  • 新表长度为原来长度的2倍,且为质数。

  • 将旧表中的关键字,通过新的哈希函数,重新填充到新表中。

由此,我们也能看到哈希表有以下缺点:

  • 当表中的元素逐渐增多时,哈希冲突的概率会增加,查找效率会下降。

  • 哈希表扩展时,需要将旧表的关键字重新哈希,迁移到新表中,性能成本大。

  • 一个好的哈希表,依赖哈希函数的合理性。

七、完美哈希

完美哈希(Perfect Hashing),是一种解决哈希冲突的方法,它通过构建一个无冲突的哈希函数来实现。

完美哈希通过两级哈希的方式来解决哈希冲突。首先,使用一个一级哈希函数将键映射到一组桶(bucket)中。然后,在每个桶中,使用二级哈希函数将键映射到具体的索引位置。通过这种方式,每个键都被映射到唯一的索引位置,从而实现了完全散列。

完美哈希在某些特定场景下非常有用,特别是当键的集合是已知的且静态的情况下。它可以在预处理阶段构建完全散列函数,然后在查询时实现O(1)的查找时间复杂度,而无需处理冲突。然而,构建完美哈希函数的过程可能会比较复杂且耗时,特别是在键的集合较大的情况下。

需要注意的是,完美哈希并不适用于动态的键集合,因为当键的数量发生变化时,可能需要重新构建哈希函数。

八、一些使用哈希解决的算法题

  1. 两数之和:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数的索引。可以使用哈希表来存储数组元素和其索引的映射关系,然后遍历数组,查找目标值与当前元素的差值是否存在于哈希表中。
    两数之和 https://blog.csdn.net/qq_41099859/article/details/112464038

  2. 两个数组的交集:给定两个整数数组,求它们的交集。可以使用哈希集合来存储一个数组中的元素,然后遍历另一个数组,判断元素是否存在于哈希集合中。
    两个数组的交集 https://blog.csdn.net/ShenHang_/article/details/107319514

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

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

相关文章

机器学习基础Matplotlib绘图

一、运行环境 学习工具:jupyter-notebookpython版本:311系统:Win11 二、什么是matplotlib? matplotlib是基于python生态开发的一个可视化绘图库,它的出现让python在数据分析及机器学习方面占了重要的一部分&#…

springBoot的实现原理;SpringBoot是什么;使用SpringBoot的核心功能;springBoot核心注解以及核心配置文件

文章目录 springBootspringBoot的实现原理什么是 Spring Boot?SpringBoot是什么为什么要使用springBootSpring Boot的核心功能Spring Boot 主要有如下优点: SpringBoot启动过程-流程Spring Boot 的核心注解是哪个?什么是 JavaConfig&#xff…

echarts 通用线性渐变堆叠面积图

echarts 通用线性渐变堆叠面积图 getLineData2() {const myChart echarts.init(this.$refs.chartDom);const option {tooltip: {trigger: axis,},legend: {show: false,textStyle: {fontSize: 14, //字体大小color: #ffffff, //字体颜色},data: [AAA, BBB],},grid: {show: tr…

汽车功能安全ISO26262

一、功能安全基本概念及功能安全管理 什么是功能安全 相关标准: 现状: 功能安全的目的和范围: 总体框架: 基本定义:

TypeError: ‘_io.TextIOWrapper’ object is not subscriptable

TypeError: ‘_io.TextIOWrapper’ object is not subscriptable表示文件不能用下标进行索引。改正代码如下即可正常运行: 错误代码示范: file_name /test.txt with open(file_name,r, encodingutf-8) as name:a name[1] #取name的第二行数据 改正之…

下载文件并重命名

//下载文件并重命名 // 无需数字化归档模版下载 function nodigitalMeth(){ let filenameunescape("/projectapp/ghsjy/template/noNeedDigital.docx")//原文件为英文名字 downloadFileRename(filename,"无需成果数据汇交模版") } // 需要数字化归档模版下…

有哪些可信的SSL证书颁发机构?

目前市面上所显示的SSL证书颁发机构可所谓不计其数,类型也是多样,就好比我们同样是买一件T恤,却有百家不同类型的店铺一个道理。根据CA里面看似很多,但能拿到99%浏览器及设备信任度的寥寥无几,下面小编整理出几家靠谱可…

MySQL 教程 1.3

上期网友笔记整理 记录 MySQL 学习过程遇到的问题。 系统:win32 位 MySQL 版本:5.7.17-log MySQL 语法对大小写不敏感,但是大写更容易看出。 一、启动关闭MySQL服务 1【开始菜单】搜索 services.msc 打开 windows【服务管理器】&#xf…

docker (简介、dcoker详细安装步骤、常用命令)- day01

一、 为什么出现 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应…

【代码】考虑电解槽变载启停特性与阶梯式碳交易机制的综合能源系统优化调度matlab-yalmip-cplex/gurob

程序名称:考虑电解槽变载启停特性与阶梯式碳交易机制的综合能源系统优化调度 实现平台:matlab-yalmip-cplex/gurobi 代码简介:提出了一种考虑 变载启停特性的电解槽混合整数线性模型,根据电 氢负荷可以实时调整设备工作状态&…

视频格式转换:将MP4轻松转MKV格式,高效便捷

随着科技的发展,数字媒体已经深入到生活中,视频格式的转换也成为了许多人的日常要求。MP4和MKV是两种常见的视频格式,它们各有优点。MP4以其高效的压缩比和广泛的兼容性被广泛使用,而MKV则因其强大的封装能力和无损压缩而受到喜爱…

英语语法:连词or, and, if, unless怎么用?

连词or, and, if, unless怎么用?1. or conj. 或者,还是, 和, 否则用法:并列连词①当“或者,还是”讲时,用在选择疑问句中,是选择疑问句的标志例:Are you a teacher or a …

阻塞队列介绍(二)

3 LinkedBlockingQueue 3.1 LinkedBlockingQueue的底层实现 查看LinkedBlockingQueue是如何存储数据&#xff0c;并且实现链表结构的。 // Node对象就是存储数据的单位 static class Node<E> { // 存储的数据 E item; // 指向下一个数据的指针 Node<E> next; //…

C++多线程学习(三):锁资源管理和条件变量

参考引用 C11 14 17 20 多线程从原理到线程池实战代码运行环境&#xff1a;Visual Studio 2019 1. 利用栈特性自动释放锁 RAII 1.1 什么是 RAII RAII (Resource Acquisition Is Initialization)&#xff1a;使用局部对象来管理资源的技术称为资源获取即初始化 它的生命周期是…

快速了解软件工程学概述(5种软件过程模型)

目录 1 、什么是软件&#xff1f;特点有哪些 &#xff1f; 2 、 软件危机 定义&#xff1a; 软件危机产生的原因 消除软件危机的方法 3 、软件工程 1.软件工程的介绍 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;本质特征 (3)软件工程方法学&#xff08;方…

十八数字文化受邀参加版博会“区块链+版权”创新应用试点研讨会

2023年11月23日至25日&#xff0c;以“版权新时代 赋能新发展”为主题的第九届中国国际版权博览会在成都市中国西部国际博览城和天府国际会议中心举办。版博会是我国版权领域唯一的综合性、国际性、国家级版权专业博览会&#xff0c;本届版博会由国家版权局主办&#xff0c;四川…

宏工科技通过CMMI三级认证,软件研发能力获国际权威认可

近日&#xff0c;宏工科技子公司湖南宏工软件成功通过CMMI三级认证并正式获得资质证书&#xff0c;斩获全球软件领域最权威的认证之一&#xff0c;标志着宏工科技在软件技术开发、研发管理、项目管理等多方面获得国际权威认证。 CMMI全称是Capability Maturity Model Integrati…

ESXi 6.7 升级 7.0

方式一&#xff1a;esxcli方式 1.登陆exsi web界面。 启用控制台shell 2.存储-datastore-数据存储浏览器&#xff0c;上载 ESXI-7.0.0-depot.zip升级文件。记住此datastore的位置 ssh连接ESXI主机 vmware -vl 查看当前版本 查看升级包中对应的版本信息&#xff1a; es…

3D模型材质编辑器

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 材质贴图&#xff08;Texture Mapping&#xff09;&#xff1a;是在物体着色方面最引人注目、…

使用 yum 出现 Loaded plugins: fastestmirro

&#x1f4d1;前言 本文主要是使用 yum 出现 Loaded plugins: fastestmirro&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…