发生冲突时哈希表如何读取正确的值?

Posted

技术标签:

【中文标题】发生冲突时哈希表如何读取正确的值?【英文标题】:How does hashtable read correct values in case of collision? 【发布时间】:2017-06-01 12:25:49 【问题描述】:

我有一些哈希表。例如,我有两个实体,如

john =  1stname: jonh, 2ndname: johnson ,
eric =  1stname: eric, 2ndname: ericson 

然后我将它们放入哈希表中:

ht["john"] = john;
ht["eric"] = eric;

让我们假设有一个冲突和哈希表使用链接来修复它。因此,应该有一个包含这两个实体的链表,例如 this hashtable 如何理解 key 应该返回什么实体?哈希值是相同的,它对实体结构一无所知。例如,如果我写 thisvar val = ht["john"]; 哈希表(只有键值及其哈希)如何发现该值应该是 john 记录而不是 eric

【问题讨论】:

看看this 【参考方案1】:

我认为您对哈希表相邻列表中每个位置存储的内容感到困惑。您似乎假设只存储了值。实际上,每个列表节点中的数据都是一个元组(key, value)。

一旦您请求ht['john'],哈希表就会找到与hash('john') 关联的列表,如果该列表不为空,它会在列表中搜索键'john'。如果找到键作为元组的第一个元素,则返回值(元组的第二个元素)。如果没有找到key,则说明该元素不在hashtable中。

总而言之,key hash 用于快速识别元素所在的单元格(如果存在)。测试实际的键相等性以确定键是否存在。

【讨论】:

在复杂对象的情况下键相等如何工作?哈希表中的值是具有不同属性的对象,但您仅使用键来获取它。 Hashtable 不知道对象结构以及我使用该对象的什么属性作为键。 看起来我明白了。我想哈希表应该将完整的键与整个对象保持在一起,以定义该键是否等于所需的键,对吧? 正如我在答案中提到的,密钥与对象一起存储在哈希表中:(key, value)。在您的情况下,键是价值的一部分,但并非总是如此。因此,哈希表在找到您搜索的键之前根本不关心您的值。然后它返回关联的值而不以任何方式对其进行分析。 另外我开始阅读 c# 字典的源代码,我看到它在内部将 key 和 value 保持在一起。【参考方案2】:

这是你要求的吗?我已经把它放在 cmets 但在我看来你没有点击链接

Hashtable 类中的冲突解决

回想一下,当向哈希表中插入项目或从哈希表中检索项目时,可能会发生冲突。插入项目时,必须找到一个开放的插槽。检索项目时,如果实际项目不在预期位置,则必须找到它。早些时候,我们简要研究了两种共谋解决策略:

线性探测 二次探测

Hashtable 类使用了一种不同的技术,称为 rehasing。 (一些来源将重新散列称为双重散列。)

重新哈希的工作方式如下:有一组不同的哈希函数,H1 ... Hn,当从哈希表插入或检索项目时,最初使用 H1 哈希函数。如果这导致了冲突,则尝试使用 H2,如果需要,可以继续尝试 Hn。上一节只展示了一个哈希函数,即初始哈希函数(H1)。其他散列函数与此函数非常相似,只是通过乘法因子来区分。一般来说,散列函数Hk定义为:

Hk(key) = [GetHash(key) + k * (1 + (((GetHash(key) >> 5) + 1) % (hashsize – 1)))] % hashsize

数学说明 在进行重新哈希时,重要的是哈希表中的每个槽在进行 hashsize 数量的探测时只被访问一次。也就是说,对于给定的键,您不希望 Hi 和 Hj 散列到散列表中的同一槽。使用 Hashtable 类使用的重新散列公式,如果 (1 + (((GetHash(key) >> 5) + 1) % (hashsize – 1)) 和 hashsize 的结果是相对质数,则保留此属性。 (如果两个数没有共同因子,则它们是互质的。)如果 hashsize 是质数,则这两个数保证是互质的。 与线性或二次探测相比,重新设置可提供更好的碰撞避免。

sources here

【讨论】:

以上是关于发生冲突时哈希表如何读取正确的值?的主要内容,如果未能解决你的问题,请参考以下文章

字典与哈希表(HashMap)

哈希表原理及如何避免键值冲突法?

哈希表中的冲突概率

Hash冲突的解决方法

发生冲突后在哈希表中实现链接时出现分段错误

哈希表之三冲突解决