`

转--解决hash冲突的三个方法

 
阅读更多

转--解决hash冲突的三个方法

 

这个东西没怎么看懂  希望被问到时有个印象

目录

  1. 开放定址法
    1. 线性探测再散列
    2. 二次探测再散列
    3. 伪随机探测再散列
  2. 再哈希法
  3. 链地址法
  4. 建立公共溢出区
  5. 优缺点
    1. 开放散列(open hashing)/ 拉链法(针对桶链结构)
    2. 封闭散列(closed hashing)/ 开放定址法

通过构造性能良好的哈希函数,可以减少冲突,但一般不可能完全避免冲突,因此解决冲突是哈希法的另一个关键问题。创建哈希表和查找哈希表都会遇到冲突,两种情况下解决冲突的方法应该一致。下面以创建哈希表为例,说明解决冲突的方法。常用的解决冲突方法有以下四种:

开放定址法

这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:

Hi=(H(key)+di)% m   i=1,2,…,n

其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:

线性探测再散列

dii=1,2,3,…,m-1

这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

二次探测再散列

di=12,-12,22,-22,…,k2,-k2    ( k<=m/2 )

这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

伪随机探测再散列

di=伪随机数序列。

 

具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。

例如,已知哈希表长度m=11,哈希函数为:H(key)= key  %  11,则H(47)=3,H(26)=4,H(60)=5,假设下一个关键字为69,则H(69)=3,与47冲突。

如果用线性探测再散列处理冲突,下一个哈希地址为H1=(3 + 1)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 + 2)% 11 = 5,还是冲突,继续找下一个哈希地址为H3=(3 + 3)% 11 = 6,此时不再冲突,将69填入5号单元。

如果用二次探测再散列处理冲突,下一个哈希地址为H1=(3 + 12)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 - 12)% 11 = 2,此时不再冲突,将69填入2号单元。

如果用伪随机探测再散列处理冲突,且伪随机数序列为:2,5,9,……..,则下一个哈希地址为H1=(3 + 2)% 11 = 5,仍然冲突,再找下一个哈希地址为H2=(3 + 5)% 11 = 8,此时不再冲突,将69填入8号单元。

再哈希法

这种方法是同时构造多个不同的哈希函数:

Hi=RH1(key)  i=1,2,…,k

当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

链地址法

这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

 

建立公共溢出区

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

 


 

优缺点

开放散列(open hashing)/ 拉链法(针对桶链结构)

1)优点: ①对于记录总数频繁可变的情况,处理的比较好(也就是避免了动态调整的开销) ②由于记录存储在结点中,而结点是动态分配,不会造成内存的浪费,所以尤其适合那种记录本身尺寸(size)很大的情况,因为此时指针的开销可以忽略不计了 ③删除记录时,比较方便,直接通过指针操作即可

 

2)缺点: ①存储的记录是随机分布在内存中的,这样在查询记录时,相比结构紧凑的数据类型(比如数组),哈希表的跳转访问会带来额外的时间开销 ②如果所有的 key-value 对是可以提前预知,并之后不会发生变化时(即不允许插入和删除),可以人为创建一个不会产生冲突的完美哈希函数(perfect hash function),此时封闭散列的性能将远高于开放散列 ③由于使用指针,记录不容易进行序列化(serialize)操作

封闭散列(closed hashing)/ 开放定址法

1)优点: ①记录更容易进行序列化(serialize)操作 ②如果记录总数可以预知,可以创建完美哈希函数,此时处理数据的效率是非常高的

 

2)缺点: ①存储记录的数目不能超过桶数组的长度,如果超过就需要扩容,而扩容会导致某次操作的时间成本飙升,这在实时或者交互式应用中可能会是一个严重的缺陷 ②使用探测序列,有可能其计算的时间成本过高,导致哈希表的处理性能降低 ③由于记录是存放在桶数组中的,而桶数组必然存在空槽,所以当记录本身尺寸(size)很大并且记录总数规模很大时,空槽占用的空间会导致明显的内存浪费 ④删除记录时,比较麻烦。比如需要删除记录a,记录b是在a之后插入桶数组的,但是和记录a有冲突,是通过探测序列再次跳转找到的地址,所以如果直接删除a,a的位置变为空槽,而空槽是查询记录失败的终止条件,这样会导致记录b在a的位置重新插入数据前不可见,所以不能直接删除a,而是设置删除标记。这就需要额外的空间和操作。

原:https://www.cnblogs.com/wuchaodzxx/p/7396599.html

分享到:
评论

相关推荐

    【精品】链地址法解决Hash冲突

    ### 链地址法解决Hash冲突 #### 一、引言 哈希表是一种非常高效的数据结构,通过哈希函数可以快速地定位到数据所在的存储位置。然而,在实际应用中,由于哈希函数的设计和数据分布的原因,经常会出现多个不同的...

    C++实现的hash冲突解决算法

    3. **再哈希法**:使用多个不同的哈希函数,当第一次哈希冲突时,使用第二个哈希函数计算新的位置,如果再次冲突,使用第三个哈希函数,以此类推。这种方法可以减少冲突,但需要设计好的哈希函数,避免冲突概率过大...

    STATUS-INVALID-IMAGE-HASH

    以上就是关于"STATUS-INVALID-IMAGE-HASH"错误的详细解析和解决方法。遵循这些步骤,应该能够有效地处理Chrome和Edge浏览器崩溃的问题。在执行任何修复操作之前,记得备份重要数据,以防止不必要的损失。

    前端开源库-key-hash

    三、`key-hash`库的使用方法 `key-hash`库的使用非常直观。首先,你需要在项目中引入这个库,如果是使用npm,可以执行`npm install key-hash`或者`yarn add key-hash`来安装。然后,在代码中引用并使用: ```...

    20151910042-刘鹏-DSA思考题-10 - Graph Traversal and Hash Table1

    - map的三个基本操作是插入、删除和查找。它通常支持根据键的顺序访问元素,而优先队列则按优先级顺序处理元素。 - 优先队列的基本操作包括插入元素、删除最小元素(最大元素)和检查最小元素。 9. **哈希码构造...

    利用Hash技术统计C源程序中关键字的频度

    用线性探测法解决Hash冲突。设Hash函数为:Hash(Key)=[(Key的首字母序号)*100+(Key的尾字母序号)] Mod 41。关键字39个,参考C语言教材。 二、数据结构设计 ①关键字表的存储结构;②Hash表中的结点结构。频度、冲突...

    hash散列表的三种实现

    双重散列表(Double Hashing)是另一种解决哈希冲突的方法,它使用两个哈希函数,当第一次哈希计算后出现冲突,会使用第二个哈希函数计算偏移量,然后再去查找新的位置。这样可以避免线性探测法中的“聚集”问题,...

    基于Java的实例源码-哈希计算工具 Java-hash.zip

    例如,我们可以期待看到一个名为`HashCalculator`或类似的类,该类使用`MessageDigest`计算文件或字符串的哈希值,并可能提供方法如`calculateMD5Hash()`、`calculateSHA1Hash()`等。 在源码中,开发者可能使用了...

    打造最快的Hash表(和Blizzard的对话)

    Blizzard的解决方案不仅仅是使用一个散列值,而是使用三个散列值来提高精确度。这种方法减少了冲突的可能性,提高了查找效率。具体实现涉及到对原始字符串应用不同的散列函数,从而获得多个散列值。 例如,在MPQ...

    HashMap-hash原理

    这个过程通常通过调用对象自身的`hashCode()`方法来完成,该方法由`Object`类提供,但通常被子类重写以提供更具体的实现。`HashMap`的内部实现会调用键对象的`hashCode()`方法,然后对其进行一定的转换操作,以便更...

    基于Hash函数加密方法的安全性研究.pdf

    Hash函数需要满足三个关键特性:单向性、抗冲突性和映射分布均匀性。单向性保证了从预映射能够简单迅速得到散列值,而在计算上不可能构造一个预映射,使其散列结果等于某个特定的散列值。抗冲突性保证了无法产生两个...

    PyPI 官网下载 | maphash-0.1.0-py3-none-any.whl

    开发者可以利用maphash库提供的方法来降低哈希冲突的影响,提高整体性能。 总的来说,maphash-0.1.0-py3-none-any.whl这个压缩包为我们提供了一个强大且易用的哈希工具,尤其适合Python 3的开发者。通过理解和掌握...

    redis-存储结构1

    渐进式Rehash机制是Redis解决Hash表冲突的方法。当Hash表中的数据增加时,Redis会创建一个新的Hash表,然后逐步将旧的Hash表中的数据迁移到新的Hash表中。这个过程叫做Rehash。Rehash机制可以使得Hash表的查找时间...

    mmu-hash32.rar_Table

    `mmu-hash32.c`文件很可能是实现这些功能的源代码,包含具体的哈希表数据结构定义、哈希函数实现、冲突解决策略、扩展性和优化措施等。通过分析这个源文件,可以深入了解Linux内核32位MMU的内部工作机制,这对于理解...

    从头到尾彻底解析Hash_表算法

    - **冲突解决策略**:哈希表中可能出现多个键值映射到同一位置的情况,即冲突。常见的解决策略包括开放寻址法(例如线性探测再散列、二次探测再散列等)和链地址法(使用链表或红黑树等数据结构)。 - **负载因子的...

    基于Java的哈希计算工具 Java-hash.zip

    SHA-1(Secure Hash Algorithm 1)和SHA-256则提供更强大的安全性和抗冲突性,分别产生160位和256位的哈希值。 在Java-hash.zip压缩包中,`src`目录可能包含了实现哈希计算功能的源代码。这些源代码可能包括以下几...

    C++哈希表使用的好文章-Hash_Map

    由于哈希函数可能造成不同的key映射到同一个桶(冲突),`hash_map`通常使用开放寻址法或链地址法来解决这个问题。开放寻址法是在冲突时寻找下一个空的桶,而链地址法则是将冲突的key-value对链接在一起。 `hash_...

    HASH算法应用的VC演示实例程序

    提供的三个压缩包文件可能是包含不同哈希算法实现的源代码示例,有助于读者深入理解哈希算法的实际操作。 哈希算法,又称为散列函数,是一种从任意大小的数据输入(通常称为预映射或消息)产生固定大小的输出(哈希...

Global site tag (gtag.js) - Google Analytics