0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于哈希表冲突解决策略解析

454398 来源:vivo互联网技术 作者:Xuegui Chen 2020-10-10 15:57 次阅读

哈希是一种通过对数据进行压缩, 从而提高效率的一种解决方法,但由于哈希函数有限,数据增大等缘故,哈希冲突成为数据有效压缩的一个难题。本文主要介绍哈希冲突、解决方案,以及各种哈希冲突的解决策略上的优缺点。

一、哈希表概述

哈希表的哈希函数输入一个键,并向返回一个哈希表的索引。可能的键的集合很大,但是哈希函数值的集合只是表的大小。

哈希函数的其他用途包括密码系统、消息摘要系统、数字签名系统,为了使这些应用程序按预期工作,冲突的概率必须非常低,因此需要一个具有非常大的可能值集合的散列函数。

密码系统:给定用户密码,操作系统计算其散列,并将其与存储在文件中的该用户的散列进行比较。(不要让密码很容易被猜出散列到相同的值)。

消息摘要系统:给定重要消息,计算其散列,并将其与消息本身分开发布。希望检查消息有效性的读者也可以使用相同的算法计算其散列,并与发布的散列进行比较。(不要希望伪造消息很容易,仍然得到相同的散列)。

这些应用的流行哈希函数算法有:

md5 : 2^128个值(找一个冲突键,需要哈希大约2 ^ 64个值)

sha-1:2^160个值(找一个冲突键,需要大约2^80个值)

二、哈希冲突

来看一个简单的实例吧,假设采用hash函数:H(K) = K mod M,插入这些值:217、701、19、30、145

H(K) = 217 % 7 = 0

H(K) = 701 % 7 = 1

H(K) = 19 % 7 = 2

H(K) = 30 % 7 = 2

H(K) = 145 % 7 = 5

上面实例很明显 19 和 30 就发生冲突了。

三、冲突解决策略

除非您要进行“完美的散列”,否则必须具有冲突解决策略,才能处理表中的冲突。

同时,该策略必须允许查找,插入和删除正确运行的操作!

冲突解决技术可以分为两类:开散列方法( open hashing,也称为拉链法,separate chaining )和闭散列方法( closed hashing,也称为开地址方法,open addressing )。这两种方法的不同之处在于:开散列法把发生冲突的关键码存储在散列表主表之外,而闭散列法把发生冲突的关键码存储在表中另一个槽内。

下面介绍业内比较流行的hash冲突解决策略:

线性探测(Linear probing)

双重哈希(Double hashing)

随机散列(Random hashing)

分离链接(Separate chaining)上面线性探测、双重哈希、随机散列都是闭散列法,而分离链接则是开散列法。

1、线性探测(Linear probing)

插入一个值

使用散列函数H(K)在大小为M的表中插入密钥K时:

设置 indx = H(K)

如果表位置indx已经包含密钥,则无需插入它。Over

否则,如果表位置indx为空,则在其中插入键。Over

其他碰撞。设置 indx =(indx + 1)mod M.

如果 indx == H(K),则表已满!就只能做哈希表的扩容了因此,线性探测基本上是在发生碰撞时对空槽进行线性搜索。

优点:易于实施;总是找到一个位置(如果有);当表不是很满时,平均情况下的性能非常好。

缺点:表的相邻插槽中会形成“集群”或“集群”键;当这些簇填满整个阵列的大部分时,性能会严重下降,因为探针序列执行的工作实际上是对大部分阵列的穷举搜索。

简单例子

如哈希表大小M = 7, 哈希函数:H(K) = K mod M。插入这些值:701, 145, 217, 19, 13, 749

H(K) = 701 % 7 = 1

H(K) = 145 % 7 = 5

H(K) = 217 % 7 = 0

H(K) = 19 % 7 = 2

H(K) = 13 % 7 = 1(冲突) --》 2(已经有值) --》 3(插入位置3)

H(K) = 749 % 7 = 2(冲突) --》 3(已经有值) --》 4(插入位置4)

可见,如果哈希表如果不是很大,随着数据插入,冲突也会组件发生,探针遍历次数将会逐渐变低,检索过程也就成为穷举。

检索一个值

如果使用线性探测将键插入表中,则线性探测将找到它们!

当使用散列函数 H(K)在大小为N的表中搜索键K时:

设置 indx = H(K)

如果表位置indx包含键,则返回FOUND。

否则,如果表位置 indx 为空,则返回NOT FOUND。

否则设置 indx =(indx + 1)modM。

如果 indx == H(K),则返回NOT FOUND。就只能做哈希表的扩容了问题:如何从使用线性探测的表中删除键?

能否进行“延迟删除”,而只是将已删除密钥的插槽标记为空?

很明显,在线性探测很难做到,如果把位置置为空,那么如果后面的值也是哈希冲突,线性探测插入,则再也无法遍历这些值了。

2、双重哈希(Double hashing)

线性探测冲突解决方案会导致表中出现簇,因为如果两个键发生碰撞,则探测到的下一个位置对于这两个键都是相同的。

双重哈希的思想:使偏移到下一个探测到的位置取决于键值,因此对于不同的键可以不同。

需要引入第二个哈希函数 H 2(K),用作探测序列中的偏移量(将线性探测视为 H 2(K)== 1 的双重哈希)。

对于大小为 M 的哈希表,H 2(K)的值应在 1到M-1 的范围内;如果M为质数,则一个常见选择是 H2(K)= 1 +((K / M)mod(M-1))。

然后,用于双哈希的插入算法为:

设置 indx = H(K); offset = H 2(K)

如果表位置indx已经包含密钥,则无需插入它。Over

否则,如果表位置 indx 为空,则在其中插入键。Over

其他碰撞。设置 indx =(indx + offset)mod M.

如果 indx == H(K),则表已满!就只能做哈希表的扩容了

哈希表为质数情况,双重hash在实践中非常有效

双重 Hash 也见:https://blog.csdn.net/chenxuegui1234/article/details/103454285

3、随机散列(Random hashing)

与双重哈希一样,随机哈希通过使探测序列取决于密钥来避免聚类。

使用随机散列时,探测序列是由密钥播种的伪随机数生成器的输出生成的(可能与另一个种子组件一起使用,该组件对于每个键都是相同的,但是对于不同的表是不同的)。

然后,用于随机哈希的插入算法为:

创建以 K 为种子的 RNG。设置indx = RNG.next() mod M。

如果表位置 indx 已经包含密钥,则无需插入它。Over

否则,如果表位置 indx 为空,则在其中插入键。Over

其他碰撞。设置 indx = RNG.next() mod M.

如果已探测所有M个位置,则放弃。就只能做哈希表的扩容了。

随机散列很容易分析,但是由于随机数生成的“费用”,它并不经常使用。双重哈希在实践中还是经常被使用。

4、分离链接(Separate chaining)

在具有哈希函数 H(K)的表中插入键K时

设置 indx = H(K)

将关键字插入到以 indx 为标题的链接列表中。(首先搜索列表,以避免重复。)

在具有哈希函数H(K)的表中搜索键K时

设置 indx = H(K)

使用线性搜索在以 indx 为标题的链表中搜索关键字。

使用哈希函数 H(K)删除表中的键K时

设置 indx = H(K)

删除链接列表中以 indx 为标题的键

优点:随着条目数量的增加,平均案例性能保持良好。甚至超过M;删除比开放地址更容易实现。

缺点:需要动态数据,除数据外还需要存储指针,本地性较差,导致缓存性能较差。

很明显,Java7 的 HashMap 就是一种分裂链接的实现方式。

分离链哈希分析

请记住表的填充程度的负载系数度量:α = N / M。

其中M是表格的大小,并且 N 是表中已插入的键数。

通过单独的链接,可以使 α》 1 给定负载因子α,我们想知道在最佳,平均和最差情况下的时间成本。

成功找到

新键插入和查找失败(这些相同),最好的情况是O(1),最坏的情况是O(N)。让我们分析平均情况

分裂链接的平均成本

假设负载系数为 α = N / M 的表

在M个链接列表中总共分配了N个项目(其中一些可能为空),因此每个链接列表的平均项目数为:

如果查找/插入失败,则必须穷举搜索表中的链表之一,并且表中链表的平均长度为α。因此,使用单独链接进行插入或不成功查找的比较平均次数为

成功查找后,将搜索包含目标密钥的链接列表。除目标密钥外,该列表中平均还有(N-1)/ M个密钥;在找到目标之前,将平均搜索其中一半。因此,使用单独链接成功找到的比较平均次数为

当α《1时,它们分别小于1和1.5。并且即使当α超过1时,它们仍然是O(1),与N无关。

四、开散列方法 VS 闭散列方法

如果将键保留为哈希表本身中的条目,则可以使用线性探测,双重和随机哈希。.. 这样做称为“开放式寻址”,也称为“封闭式哈希”。

另一个想法:哈希表中的条目只是指向链表(“链”)头部的指针;链接列表的元素包含键。.. 这称为“单独链接”,也称为“开放式哈希”。

通过单独的链接,冲突解决变得容易:只要在其链表中插入一个键,就可以将其插入(为此,可以使用比链表更高级的数据结构;但是正如我们将看到的,链表在一般情况下效果很好)。

让下面我们看一下这些策略的时间成本。

开放式地址哈希分析

分析哈希表“查找”或“插入”性能时,一个有用的参数是负载系数 α = N / M。

其中 M 是表格的大小,并且 N 是表中已插入的键数负载系数是表满度的一种度量。

给定负载因子 α ,我们想知道在最佳,平均和最差情况下的时间成本。

成功找到

对所有键,最好的情况是O(1),最坏的情况是O(N),新键插入和查找失败(这些相同),所以让我们分析平均情况。

我们将给出随机哈希和线性探测的结果。实际上,双重哈希类似于随机哈希;

平均不成功的查找/插入成本

假定负载系数为α= N / M的表。考虑随机散列,因此聚类不是问题。每个探针位置是随机且独立生成的对于每个探针,找到空位置的可能性为(1-α)。查找空位置将停止查找或插入,这是一个伯努利过程,成功概率为(1-α)。该过程的预期一阶到达时间为 1 /(1-α)。所以:

使用随机哈希进行插入或不成功查找的探针的平均数量为

使用线性探测时,探头的位置不是独立的。团簇形成,当负载系数高时会导致较长的探针序列。可以证明,用于线性探测的插入或未成功发现的探针的平均数量约为

当 α 接近1时,这些平均案例时间成本很差,仅受M限制;但当 α 等于或小于7.75(与M无关)时,效果还不错(分别为4和8.5)

平均成功查找成本

假定负载系数为 α= N / M 的表。考虑随机散列,因此聚类不是问题。每个探针位置是随机且独立生成的。

对于表中的键,成功找到它所需的探针数等于将其插入表中时所采用的探针数。每个新密钥的插入都会增加负载系数,从0开始到α。

因此,通过随机散列成功发现的探测器的平均数量为

通过线性探测,会形成簇,从而导致更长的探针序列。可以证明,通过线性探测成功发现的平均探针数为

当α接近1时,这些平均案例时间成本很差,仅受M限制;但当α等于或小于7.75时好(分别为1.8和2.5),与M无关。
编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 哈希函数
    +关注

    关注

    0

    文章

    43

    浏览量

    9388
  • 哈希表
    +关注

    关注

    0

    文章

    9

    浏览量

    4705
收藏 人收藏

    评论

    相关推荐

    序列化哈希到文件

    序列化哈希到文件using System;using System.Collections.Generic;using System.ComponentModel;using
    发表于 06-18 18:28

    基于多维整数空间的安全策略冲突检测与消解

    针对当前大部分安全策略冲突检测与消解算法缺少灵活性和扩展性等缺点,提出一种基于多维整数空间的安全策略形式化描述方法,在此基础上设计了一种可扩展的安全策略
    发表于 03-24 08:49 13次下载

    智能安全防护软件策略构件的设计与实现

    针对智能安全防护软件中策略的定制和管理问题,设计并实现软件的策略构件,采用基于用户最大满意度的策略选择算法解决策略选择时的策略缺失和
    发表于 04-02 08:40 15次下载

    右对齐算法解决IPsec安全策略冲突问题

    当前IPsec 的策略系统的策略设置方式很可能引起策略冲突。在分析和比较现有策略生成算法的基础上,提出了右对齐
    发表于 06-26 08:36 9次下载

    基于有向图模型的网络安全策略冲突研究

    保证安全策略的协同工作和一致性是实现分布式系统安全管理需要首先解决的问题。本文提出了一种可适应的安全策略框架,在此安全策略框架中,针对现有安全策略
    发表于 01-27 15:12 11次下载

    微电网中电能质量问题及解决策略_孟良

    微电网中电能质量问题及解决策略_孟良
    发表于 01-08 11:13 4次下载

    AVS_RS系统冲突与死锁控制策略_方彦军

    AVS_RS系统冲突与死锁控制策略_方彦军
    发表于 01-17 19:58 0次下载

    面向数据去重的基于二次哈希的收敛加密策略

    问题;(2)对重复数据的无用加密操作使得计算开销随着数据负载去重率的提高而增加。针对上述两个问题,提出了基于二次哈希的收敛加密策略(TCE)。具体而言,TCE首先计算数据块的哈希生成密钥,密钥经过可信第三方添加秘密信息后增加随机
    发表于 11-25 10:13 0次下载
    面向数据去重的基于二次<b class='flag-5'>哈希</b>的收敛加密<b class='flag-5'>策略</b>

    源网冲突度量的两层优化模型与分析

    源网冲突,以源网冲突度为核心建立了两层优化决策模型。其中,上层问题以输电元件运行状态为决策量,追求尽量少地改变上层电网结构,使源网冲突度在系
    发表于 01-25 14:20 4次下载
    源网<b class='flag-5'>冲突</b>度量的两层优化模型与分析

    哈希哈希算法的介绍

    聊到区块链的时候也少不了会听到“哈希”、“哈希函数”、“哈希算法”,是不是听得一头雾水?别急,这一讲我们来讲讲什么是哈希算法。
    的头像 发表于 05-22 14:11 5980次阅读
    <b class='flag-5'>哈希</b>及<b class='flag-5'>哈希</b>算法的介绍

    基于C++哈希表解决冲突

    开放寻址是其中一种缓解散列冲突的编程技术,当使用开放寻址作为冲突解决技术时,键值对存储在表(数组)中,而不是像单独链表那样的数据结构中。这意味着我们需要时刻留意哈希表的尺寸以及当前表中已有的元素数量。
    的头像 发表于 05-05 23:11 1733次阅读
    基于C++<b class='flag-5'>哈希</b>表解决<b class='flag-5'>冲突</b>

    计算机系统中哈希表的优化

    导读:本文从哈希表传统设计与解决思路入手,深入浅出地引出新的设计思路:从尽量规避哈希冲突,转向了利⽤合适的哈希冲突概率来优化计算和存储效率。
    的头像 发表于 03-02 14:10 1888次阅读

    一种基于智能放置策略的CucKoo哈希

    由于查询时间复杂度为O(1), Cuckoo哈希表在大数据、云计算等领域得到了广泛应用。然而,现有 Cuckoo哈希表的写入操作在遇到写冲突时普遍采用随杋替换策略来替换已有表项。一方面
    发表于 05-13 11:10 12次下载

    基于奖励机制的SAT求解器分支策略综述

    大都结合了冲突分析过程,但分支策略对参与冲突分析的变量奖励方法有所不同,因此所挑选出的决策变量会有所差异。文中考虑到决策变量总是在未赋值变量
    发表于 05-18 11:53 1次下载

    人工智能在武装冲突决策中的应用

    AI-DSS 的优势往往体现在提高态势感知能力和加快决策周期上。下文将根据人工智能系统和人类的局限性,并结合现代冲突的规划过程,对这些说法进行解读。
    发表于 10-31 14:42 167次阅读