1、链地址法

次日清晨,大臣们按时上朝,接着讨论昨日的话题。

“昨日Hash函数的选择我们已经有了具体的方案了,那就只剩下冲突的解决问题了”,王大臣率先发话。

“要解决冲突其实也不难,既然会有多个元素被Hash到同一个位置,而这个位置只能存储一个元素,那么我让这个位置可以存储多个元素不就可以了吗?”,何大臣说道。

“哦,怎么个弄法?”王大臣问道。

“用链表啊,来一个元素加一个,让这个位置存储一个指针,指向一个链表,让所有相同位置的元素都放在这个链表中”,何大臣回答道,接着又画了一个图。

“在存储的时候,如果多个元素被Hash到同一位置,那么就加入到该位置所指向的链表中,如果该位置没有元素,则为null(指向空)”,何大臣解释道。

“那个 1 和 6 谁先存放进来呢?”,思维缜密的王大人问道。

“这个当然是6了,因为这个插入链表的时候要采用‘头插’的方式,也就是插入链表的最前面(图中里数组最近的元素)”,何大人说道。

“哦,这是为什么呢?”,王大人追问道

“因为经常发生这样的事情:新加入的元素很可能被再次访问到,所以放到头的话,如果查找就不用再遍历链表了”,见多识广的何大人解释道。

2、rehash

“这样解决冲突固然好,但是也有瓶颈啊”,寡言的李大臣又发言了。

“哦,什么瓶颈?”,何大人问道。

“你看啊,假设咱们的Hash函数设计的非常好,能够将元素均匀Hash(散列)开来,但是当我们实际存入的值越来越多的时候,这个链表也势必越来越长,那当我们进行查找的时候,势必就会遍历链表,效率也就越来越慢”,李大臣回应道,顺便画了一个图。

“这样的话,随着链表的不断增长,查询某一个元素的时间也就增加了,如果链表长度远远大于数组长度,不就和用链表存储一样了吗?”,李大臣说道。

“恩恩,对,李大臣说的极是,李大臣有何高见?”,何大臣问道。

“现在只能扩大数组的长度大约为原来的两倍。然后选取一个相关的新的Hash函数(比如之前使用 key % m,现在只改变一下m的值)。将旧Hash表中所有的元素通过新的Hash函数计算出新的Hash值,并将其插入到新表中(仍然使用链表),这就叫rehash吧”,李大臣说完又画了一个图。

“这里的数组就扩大了近两倍,由于要大小要选素数,那就选原数组大小两倍后的第一个素数7,旧Hash表和新Hash表采用了不同的Hash函数,但相关,只是m的取值变了”李大臣解释道。

“哦,这样做确实是一种办法,但是问题随之而来,就是什么时候开始rehash”,何大臣说道

3、装载因子 α

“我们可以定义这样一个变量 α = 所有元素个数/数组的大小,我们叫它装载因子吧,它代表着我们的Hash表(也就是数组)的装满程度,在这里也代表链表的平均长度。比如说,我们的数组大小为 5 ,我们给里面存入 3个元素,那么 α = 3/5 =0.6, 这个Hash表装满程度为60%,平均每条链有0.6个元素,当然 α 也可以等于和大于 1 ”,李大臣说道。

“哦,引入这个装载因子有何用意?”,何大臣问道。

“这个装载因子代表了Hash表的装满程度,这里也可以代表链表的平均长度,那么也就可以代表查询时的时间长短了。

基于此,我们为了不让查询时间长,也就是查询性能低,我们可以设置一个临界 α 值,当随着存入元素导致 α 大于这个临界 α 值的时候。

我们可以通过rehash来调整当前的 α 值,使之低于我们设定的临界 α 值,从而使我们的查询性能保持在较好的范围之内”,李大臣答道。

“比如说,我们设定 临界 α = 0.7,对于一个Hash表大小为5的Hash表而言。

当存入存入第四个元素的时候,α 就超出了临界 α 值,我们可以将数组长度变为11进行rehash(因为11是原表两倍后的第一个素数),使得装载因子 α 小于 0.7”,李大臣举了一个例子并画了一个图
“通过rehash我们可以使得装载因子在一定范围内,那我们的查询性能也就得到了保证了”,李大臣说道。

“哦,那这个 临界的 α 值应该选择多大呢?”何大臣追问道。

“这个 临界 α 如果选的小了,那数组的空间利用率就会太低,就比如说数组大小为100,α = 0.01,那装满程度为1%,99%还没有被利用。

如果 α 太大了,那冲突就会很多,比如说 数组大小为 5,α = 10, 那平均每条链有10个元素,装满程度为1000%。

即使Hash函数设计的合理,基本上每次存放元素的时候就会冲突,所以鉴于两者之间我觉得 0.6 - 0.9 之间是一个不错的选择,不妨选0.75吧”,李大臣回答道。

大家一致同意

最后的总结

“这两天辛苦众爱卿了,你们的方案非常好,我也听了听。我们这种用Hash函数将关键字和关键字地址建立起来的映射,对我们的查找非常有帮助。其中非常重要的关键点就是:哈希函数的选择、处理冲突的方法以及装载因子调整。

HashMap底层——解决Hash冲突(链地址法)相关推荐

  1. mysql映射成hashmap_大厂面试必问!HashMap 怎样解决hash冲突?

    HashMap冲突解决方法比较考验一个开发者解决问题的能力. 下文给出HashMap冲突的解决方法以及原理分析,无论是在面试问答或者实际使用中,应该都会有所帮助. 在Java编程语言中,最基本的结构就 ...

  2. HashMap 怎样解决hash冲突?

    HashMap冲突解决方法比较考验一个开发者解决问题的能力. 下文给出HashMap冲突的解决方法以及原理分析,无论是在面试问答或者实际使用中,应该都会有所帮助. 在Java编程语言中,最基本的结构就 ...

  3. HashMap 如何解决 hash 冲突

    HashMap 底层采用数组的结构来存储数据元素,数组的默认长度是 16,通过 put 方法添加数据的时候,HashMap 根据 key 的 hash 值进行取模运算,最终保存到数组的指定位置 这种设 ...

  4. hashMap怎么解决hash冲突的

    2019独角兽企业重金招聘Python工程师标准>>> 学Java的都知道hashMap的底层是"链表散列"的数据结构也也可以说是hash表.在put的实话先根据 ...

  5. java开放地址法和链地址法解决hash冲突

    hashMap对各位小伙们来说,没有不知道的了,使用过的人想必或多或少的都了解一点hashMap的底层实现原理,总结来说就是,数组+链表,至于源码的实现,大家可参看源码,今天想说的是hashMap是怎 ...

  6. Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 参考文章: (1)Java解决Hash(散列)冲突的四种方法--开放地址法 ...

  7. Hash——哈希法概念、哈希函数构造方法、哈希冲突解决办法(重点讨论链地址法)

    声明:本篇博客根据回顾老师上课知识和书籍<数据结构--用C语言描述>(耿国华)整理得出,仅作知识回顾学习用. 1.哈希法 哈希法又称散列法.杂凑法.关键字地址计算法.相对应的表称为哈希表. ...

  8. 哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现

    哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现 参考文章: (1)哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现 (2)https://www. ...

  9. HashMap解决hash冲突的方法

    HashMap解决hash冲突的方法 博客分类: jvm虚拟机 在Java编程语言中,最基本的结构就是两种,一种是数组,一种是模拟指针(引用),所有的数据结构都可以用这两个基本结构构造,HashMap ...

最新文章

  1. test 2016-12-28
  2. 信息系统项目管理师-论文专题(三)范围管理论文写作
  3. Gooogle Test中的TEST()宏代码分析
  4. 移动APP接口安全性设计
  5. 前端学习(3271):js中this的使用
  6. 10个工程师,9个不合格!!
  7. CSS 实现DIV浮动定位不闪
  8. SpringBoot从零单排 ------ 拦截器的使用
  9. 创建服务器及请求响应等简单的node.js例子
  10. maven eclipse 编译错误 Dynamic Web Module 3.0 requires Java 1.6 or new
  11. Android内核开发:系统启动速度优化
  12. 关于NDK及安装使用
  13. Java学习网站推荐
  14. 1月22日更新-近期200+热门微信小程序demo源码下载汇总
  15. 在PSP上玩《大旋风 Twin Hawk》
  16. 防火墙 firewall 及端口查看
  17. 小程序点击图片查看详情
  18. 2022年全球与中国石油和天然气固井服务行业发展趋势及投资战略分析报告
  19. 小高不太行之前端——html网页制作
  20. 计算机桌面底边出现库如何去掉,桌面图标有蓝底怎么去掉? 去掉桌面图标阴影技巧...

热门文章

  1. 智能车浅谈——抗干扰技术软件篇
  2. 将swolidwroks文件导出URDF,导入v-rep\CoppeliaSim
  3. c语言printf函数中的格式控制字符串,C++_C语言格式化输入输出函数详解,一:格式输出函数printf() 1 - phpStudy...
  4. Flutter 插件开发:iOS篇
  5. android studio虚拟机图库不显示图片,照片显示图片解决办法
  6. 透明与不透明物体共存
  7. java mysql 分区表_mysql 分区有实用价值吗?
  8. 装甲逆袭-玩家碰撞处理
  9. 计算机函数if80到90分怎么弄,用EXCEL工作表怎样利用IF函数计算分数等级
  10. C++ 并发编程(从C++11到C++17)