【问题标题】:Implementing HashMap: Avoid collisions caused by compress function [closed]实现HashMap:避免压缩函数引起的冲突[关闭]
【发布时间】:2019-03-18 05:04:53
【问题描述】:

我正在实现一个哈希映射来包含一个单词文件中的所有单词(例如dictionary.txtbible.txt)并且我遇到了碰撞问题。我知道那里有很多很好的哈希函数,但是当我尝试使用这个压缩函数压缩哈希码时,冲突的数量会显着增加(我使用dbj2 作为我的哈希函数)。

我的 hashmap 基本上将一个键转换为其哈希值,并将该哈希值压缩为内部哈希表中条目的索引,这是一个数组。如果达到0.5load factor,它会将自身调整为2 * capacity - 1。当发生冲突时,我的 hashmap 会使用二次探测生成新的索引。

这是我当前的压缩函数的样子:

private int compress(int hashCode) {
    return Math.abs(hashCode) % capacity;
}

有什么(有效的)方法可以避免碰撞吗?改变 hashmap 本身的结构也是可以接受的。

【问题讨论】:

  • 没有充分的理由发生大量冲突,除非您的哈希算法很差。请向我们展示更多代码。在这种情况下,Math.abs() 也可能不会像您认为的那样做。阅读文档。

标签: java hash hashmap hash-collision


【解决方案1】:

您对哈希码的“压缩”正在将一个相对较好的哈希函数变成一个较差的哈希函数。

基本上只有一个实用的解决方案。别这样了。只需使用完整的 32 位哈希码。它们是不可压缩的。任何减少哈希码大小的行为都会不可避免地增加冲突率。


将 32 位哈希码映射到数组索引的问题是另一回事。为此,您应该使用hashcode % array.length

如果这给你带来了过高的冲突率,那么要么你的原始哈希函数很差,要么你的实现中存在一些其他错误或设计问题,或者......你只是运气不好。

但这也可能是您收集碰撞统计数据的方式有问题,或者您的期望有问题。


还值得注意的是,您使用的是open addressing 方案。维基百科的文章是这样说的:

所有这些开放寻址方案的一个缺点是存储的条目数不能超过桶数组中的槽数。事实上,即使使用良好的散列函数,当负载因子超过 0.7 左右时,它们的性能也会急剧下降。对于许多应用程序,这些限制要求使用动态调整大小,并随之产生成本。

事实上,如果你仔细想想,any 开放寻址方案中的冲突影响比使用单独的哈希链时更明显。


最后,从头开始实现高性能哈希表是很困难的,尤其是,如果您没有先阅读有关该主题的文献。 (在 StackOverflow 上提问并不是进行研究的好方法!)

【讨论】:

  • 但是我使用一个数组作为哈希表。如何拟合 32 位哈希码以将其用作小型数组的索引?
【解决方案2】:

我建议使用双散列算法。

  • 它将通过为冲突的键提供不同的搜索路径来避免聚类
  • 恒定时间搜索/插入
  • 更高的负载系数 (a),这将允许您使用更小的表(压缩)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 2022-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多