Hash学习(3)-冲突的解决
为提高hash表查找性能,除了考虑选择合适的hash表表长和完美的hash函数外,还必须考虑hash表处理冲突的能力。当hash函数对两个不同的数据项产生了相同的hash值时,冲突就产生了。对于冲突的处理,通常采用的方法可以分为三类:
(1)线性再散列法,简单的按顺序遍历hash表,寻找下一个可用的槽;
(2)非线性再散列法,计算一个新的hash值;
(3)外部拉链法,将hash表中的每个槽当作具有相同hash值的数据项所组成链表的头部,hash表将发生冲突的项添加到同一个链表中。
下面对这三种方法分别介绍。
1.线性再散列法
线性再散列法是形式最简单的处理冲突的方法。插入元素时,如果发生冲突,算法会简单的遍历hash表,直到找到表中的下一个空槽,并将该元素放入该槽中。查找元素时,首先散列值所指向的槽,如果没有找到匹配,则继续遍历hash表,直到:(1)找到相应的元素;(2)找到一个空槽(指示查找的元素不存在);(3)整个hash表遍历完毕(指示该元素不存在并且hash表是满的)。下表显示了以线性再散列法将{89,18,49,58,69}5个元素插入hash表的过程。(hash函数为:hash(X)=X mod 10;hash表长一般用素数,这里为了说明方便取表长为10)
第一次冲突发生在插入关键字49时,它被放在下一个空闲地址,即地址0。关键字58依次和18,89,49发生冲突,试选三次之后才找到一个空单元。对69的冲突用类似的方法处理。从以上过程可以看出,只要表中有空闲单元,总可以找到,但这里选择步长为1,将会在hash表中产生聚集,即:即使hash表相对较空,还是会在某些区域形成一些区块,这些区块中的任何活动都将设计更大的步长。但如果以5或更大的值作为步长,可以迅速地从拥挤区域移开,从而减少聚集现象的发生。事实上,只要hash表长和检查槽的步长是互质的,那么表中的每个槽都会被检查到。
线性再散列法有两个缺点:第一,不能从表中删除元素,因为相应的单元可能已经引起过冲突,元素绕过它存到了别处,例如,如果我们删除了18,那么其他的元素都会找不到。如果确实需要删除,可以采用懒惰删除的方法。第二,当表被填满时性能下降明显。
2.非线性再散列法
线性再散列法是从冲突位置开始,采用一个步长以顺序方式遍历hash表,来查找一个可用的槽,从上面的讨论可以看出,它容易产生聚集现象。非线性再散列法可以避免遍历散列表,它会计算一个新的hash值,并通过它跳转到表中一个完全不同的部分。它的思想就是:通过跳转到表中不同的部分,从而避免相似值的聚集,如果再散列函数跳转到的槽已经被占用了,则继续执行新一轮的再散列和跳转。
例如,还是上面的例子,如果再散列函数是hash(X)=R-(X mod R),其中R为小于hash表长的素数,如果我们选择R=7,则下表显示了插入与前面相同的关键字的结果。
第一个冲突发生在49被插入的时候, hash(49)=7-0=7,故49被插入到位置6。Hash(58)=7-2=5,于是58被插入到位置3。最后69产生冲突,从而被插入到距离为hash(69)=7-6=1的地方。
非线性再散列法也有不能从表中删除元素的缺点。
无论是使用线性再散列法还是非线性再散列法,只有在散列表不会接近填满的情况下,才能使用再散列。当散列表的负载因子增大时,再散列所花费的时间也会显著增加。通过以上讨论可以看出,再散列方法适用于表负载较低并且不太可能执行删除操作的情况。
3.外部拉链法
外部拉链法是将hash表看作是一个链表数组,表中的每个槽要不为空,要不指向hash到该槽的表项的链表。可以通过把元素添加到链表中来解决冲突。同样,可以通过从链表中删除元素来执行删除操作。因此,解决冲突的代价不会超过向链表中添加一个节点,不需要执行再散列。在再散列中,表项的最大数量是由表中槽的原始数量确定的,与之不同的是,外部拉链法可以容纳的元素于将在内存中存放的元素一样多。
外部拉链法的原则是:hash表的大小一般与预料的元素个数差不多。
假设有一个表长为10的hash表,给出10个关键字为前10个自然数的平方,hash函数为hash(X)=X mod 10,下图就是对应的外部拉链法的hash表。
外部拉链法的平均查找时间是对链表的查找时间加上1,这个1是最初的定位hash表槽。外部拉链法的缺点是:它需要稍微多一些的空间来实现,因为添加任何元素都需要添加指向节点的指针,并且每次探查也要花费稍微多一点的时间,因为它需要间接引用指针,而不是直接访问元素。由于今天的内存成本很低并且可以使用非常快的CPU,所以这些缺点都是微不足道的。因此,实际使用hash表时,一般都是使用拉链法来解决hash冲突。
Hash学习(3)-冲突的解决相关推荐
- Hash冲突的解决--暴雪的Hash算法
Hash冲突的解决--暴雪的Hash算法 https://usench.iteye.com/blog/2199399 https://www.bbsmax.com/A/kPzOO7a8zx/ 转载于: ...
- Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 参考文章: (1)Java解决Hash(散列)冲突的四种方法--开放地址法 ...
- HashMap 中 hash 冲突的解决方法及原理分析
我们最先衰老的不是容貌,而是不顾一切的闯劲.有时候,要敢于背上超出自己预料的包袱,真的努力后,你会发现自己要比想象的优秀很多. HashMap冲突的解决方法比较考验一个开发者解决问题的能力. 在Jav ...
- Algorithms_算法专项_Hash算法的原理哈希冲突的解决办法
文章目录 引导案例 案例一 案例二 hash表(散列表) 哈希函数(散列函数) 哈希碰撞( 哈希冲突 ) 如何解决hash冲突(hash碰撞) 开放寻址 线性探测(LP) 二次探测 (平方探测 QP) ...
- 哈希冲突常用解决方法
文章目录 1.基本概念 2.解决哈希冲突的方法 2.1 开放寻址法 2.1.1 线性探查法 2.1.2 平方探查法 2.1.3 双散列函数探查法 2.1.4 伪随机探查法 2.1.5 小结 2.2 链 ...
- 哈希 ---《哈希函数》------除数的选取为什么是质数?、《哈希冲突》------解决方法、《闭散列》、《开散列》
一.哈希概念 顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较**.顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN ) ...
- 哈希表及哈希冲突的解决
哈希表(也叫关联数组)一种通用的数据结构,哈希表是一种通过关键码去寻找值得数据映射结构 例:新华字典.如果我想知道"按"的详细信息,根据拼音去查找拼音索引,首先查找"an ...
- 【SVN】在Windows系统上进行SVN的基本操作(检出,更新,提交,分支合并分支,还原,制造冲突以及解决冲突,忽略)
介绍 这里是小编成长之路的历程,也是小编的学习之路.希望和各位大佬们一起成长! 以下为小编最喜欢的两句话: 要有最朴素的生活和最遥远的梦想,即使明天天寒地冻,山高水远,路远马亡. 一个人为什么要努力? ...
- TextView AutoLink, ClikSpan 与长按事件冲突的解决,Android面试真题解析火爆全网
} } } 首先调用 Linkify.addLinks 方法解析 autolink 的相关属性 判断是否 mLinksClickable mLinksClickable && !tex ...
- 关于Android滑动冲突的解决方法(二)
之前的一遍学习笔记主要就Android滑动冲突中,在不同方向的滑动所造成冲突进行了了解,这种冲突很容易理解,当然也很容易解决.今天,就同方向的滑动所造成的冲突进行一下了解,这里就先以垂直方向的滑动冲突 ...
最新文章
- 微信JS SDK Demo
- Pytorch List Tensor转Tensor,,reshape拼接等操作
- 计算机网络技术发源于什么,计算机网络基础试题和答案
- Rethinking Design Patterns - from Jeff Atwood
- 【转】卖场开设社区便利店,不仅卖货,还有家政服务、售后衔接等(图)
- svm多分类代码_监督学习——分类算法I
- 如何将多个源文件编译为一个.ko
- chrome解决跨域(CORS)问题---chrome插件
- copyleft_什么是copyleft?
- 安卓学习笔记28:文件流操作
- python:画图调整图例位置
- Java集合---概述(1)
- 关于putty中的psftp、ftp上传下载的基本操作
- 时间管理——番茄工作法
- using runtime html4,为什么我不能在C#中引用System.Runtime.Serialization.Json
- 电机控制中标幺的目的
- PPTP配置实例(HiPER ReOS 2008 ×××配置手册)
- Uboot学习笔记①---(文件目录结构、README摘要、uImage的64字节头信息)
- mysql锁描述正确的是_MySQL表锁详解
- 深入理解Java虚拟机(第三版)--经典垃圾收集器