【问题标题】:What Exactly is Hash Collision究竟什么是哈希冲突
【发布时间】:2018-01-29 10:35:57
【问题描述】:

HashMap 中的Hash Collision 或Hashing Collision 并不是一个新话题,我遇到过几个博客和讨论板,它们解释了如何产生Hash Collision 或如何以模糊而详细的方式避免它。我最近在一次采访中遇到了这个问题。我有很多事情要解释,但我认为很难准确地给出正确的解释。抱歉,如果我的问题在这里重复,请引导我找到准确的答案:

  1. 究竟什么是哈希冲突 - 它是一种功能,还是一种常见的被错误执行但最好避免的现象?
  2. 究竟是什么导致哈希冲突 - 自定义类的错误定义 hashCode() 方法,或者在不完全覆盖 hashCode() 方法的同时保留 equals() 方法不被覆盖,或者它不取决于开发人员并且许多流行的 java 库也有可能导致 Hash Collision 的类?
  3. 发生哈希冲突时是否有任何问题或意外?我的意思是我们有什么理由应该避免 Hash Collision?
  4. Java 是否在对象初始化期间生成或至少尝试为每个类生成唯一的 hashCode?如果不是,那么仅依靠 Java 来确保我的程序不会遇到 JRE 类的 Hash Collision 是否正确?如果不正确,那么如何避免以 String 等 final 类为键的 hashmap 的 hash 冲突?

如果您能分享其中一个或所有问题的答案,我将不胜感激。

【问题讨论】:

  • 我建议重新表述这个问题。而不是“分享一篇精彩的博客文章”(这对于 StackOverflow 来说是题外话),为什么不要求正确的分析和解释呢?
  • 面试问题,就像家庭作业问题一样,是你应该自己解决的问题。如果您将它们作为问题发布在 StackOverflow 上,您必须提供自己的解决方案,并指出您的解决方案卡住或缺少的地方。就目前而言,这只是一个表明缺乏研究的问题。
  • 您通常不会“避免”哈希冲突,而是您通常认为哈希映射会发生并且将会发生的事情。 Java 集合的HashMap 使用的解决方法是维护一个冲突值树(曾经是一个值列表)。如果您发现自己有太多冲突,您可能需要考虑调整哈希图中存储桶的数量。而且你的问题太宽泛了,我同意其他cmets,你应该缩小你想在这里问的范围。
  • 您确实指定这些是面试问题。所以它们与家庭作业问题相同。清脆与否 - 他们不遵循 SO 的指导方针(我很惊讶人们支持这个问题)。一方面,您应该始终在一个帖子中发布一个问题。

标签: java collections collision hash-collision


【解决方案1】:

Hash Collision 到底是什么 - 它是一种功能,还是一种被错误完成但很好避免的常见现象?

这是一个功能。它源于 hashCode 的本质:从大值空间到小得多的值空间的映射。出于设计和意图,将会发生碰撞。

究竟是什么导致了Hash Collision - 自定义类的hashCode()方法的错误定义,

糟糕的设计会使情况变得更糟,但它在概念中很普遍。

或者不覆盖 equals() 方法,同时不完全覆盖 hashCode() 方法,

没有。

或者这不是由开发人员决定的吗?许多流行的 Java 库也有可能导致 Hash Collision 的类?

这真的没有意义。哈希注定迟早会发生冲突,而糟糕的算法可以使其更快。就是这样。

Hash Collision 发生时有什么问题或意外吗?

如果哈希表写得很好,则不会。哈希冲突只意味着哈希代码不是唯一的,这会让你调用equals(),并且重复越多性能越差。

我的意思是我们有什么理由应该避免哈希冲突?

您必须在计算的简易性与值的传播之间进行权衡。没有单一的黑白答案。

Java 是否在对象初始化期间生成或至少尝试为每个类生成唯一的 hasCode?​​p>

没有。 “唯一哈希码”是一个自相矛盾的术语。

如果不是,那么仅依靠 Java 来确保我的程序不会遇到 JRE 类的 Hash Collision 是否正确?如果不正确,那么如何避免以 String 作为 key 的 final 类的 hashmap 的 hash 冲突?

这个问题毫无意义。如果您使用String,则您对哈希算法没有任何选择,并且您还使用了一个其 hashCode 已被专家奴役二十年或更长时间的类。

【讨论】:

  • 感谢您花时间回答每个问题。我只是想了解答案以及我已经知道和学到的东西。在接受这个作为“答案”之前,我会急切地等待看到更多的答案,或者可能是更多关于“哈希碰撞发生时是否有任何问题或意外?我的意思是我们有什么理由让我们应该避免 Hash Collision 吗?”
  • @sribasu 我并不是要破坏 EJP 的好答案 +1,但是当发生哈希冲突时,您将面临地图性能下降的风险。为什么是这样?因为现在当你有一个键时,你不能只查找值,每个键现在都指向某种辅助数据结构(例如列表、树等)。在最坏的情况下,Java 8 HashMap 的性能与平衡二叉树相同。不可怕,但肯定不是O(1) 查找,而是O(lgN) 查找。
  • @TimBiegeleisen 再次感谢,现在我可以匹配我之前学到的东西。我了解到哈希冲突会导致性能下降,如果可能的话,最好始终避免。我在一篇文章中读到平衡二叉树是在 Java 8 中引入的。在此之前,它是通过链表进行链接的。甚至 Java 8 也维护 Linked List 并且仅当冲突键(重复)计数超过默认设置为 8 的某个阈值(可配置)时才将存储桶移动到平衡二叉树。这些信息正确吗?
  • @sribasu 是的,这听起来很正确,可能直接取自 Javadoc。但是你不会“避免”碰撞,就像你通过不醉酒驾驶或在暴风雪中驾驶来避免车祸一样。相反,HashMap 的实现已经被优化以调整桶的数量,通常,当您的地图最终处于可能发生冲突的情况时。增加桶,减少碰撞的机会,但你需要更多的地图空间。这是一个权衡。
  • @sribasu 我已经回答了有关“有什么问题”等问题。我没有什么要补充的;我也没有看到其他人添加了任何东西。我不知道你还在寻找什么。
【解决方案2】:

其实我认为哈希冲突是正常的。先说一个案例来思考。我们有 1000000 个大数(x 的集合 S),假设 x 在 2^64 中。现在我们想为这个数字集做一个映射。让我们将此数字集 S 映射到 [0,1000000] 。

但是怎么做呢?使用哈希!!

定义一个哈希函数f(x) = x mod 1000000。现在S中的x会转换成[0,1000000),OK,但是你会发现S中的很多数都会转换成一个数。例如。数字 k * 1000000 + y 将全部位于 y 中,因为 (k * 1000000 + y) % x = y。所以这是一个哈希冲突。

以及如何处理碰撞?在我们上面谈到的这种情况下,很难界定碰撞,因为数学计算有一些可能性。我们可以找到更复杂、更好的散列函数,但不能肯定地说我们消除了碰撞。我们应该努力寻找更好的哈希函数来减少哈希冲突。因为哈希冲突增加了我们使用哈希查找东西的时间成本。

简单来说有两种处理哈希冲突的方法。链表是一种更直接的方式,例如:如果上面的两个数在hash_function之后得到相同的值,我们就从这个值桶中创建一个链表,所有相同的值都放入该值的链表中。另一种方法是为后面的号码找到一个新的位置。例如,如果数字 1000005 占据了 5 的位置,当 2000005 得到值 5 时,它无法定位到位置 5,然后它继续寻找一个空位置来占据。

对于最后一个问题:Java 是否在对象初始化期间生成或至少尝试为每个类生成唯一的 hashCode?​​p>

Object 的 hashcode 通常是通过将对象的内部地址转换为整数来实现的。所以你可以认为不同的对象有不同的hashcode,如果你使用对象的hashcode()。

【讨论】:

    【解决方案3】:

    Hash Collision 到底是什么 - 它是一种功能,还是一种常见的被错误完成但最好避免的现象?

    • 哈希冲突就是这样,该字段哈希码在对象上的冲突...

    究竟是什么导致了 Hash Collision - 自定义类的 hashCode() 方法的错误定义,或者离开 equals() 方法 在未完全覆盖 hashCode() 方法时未覆盖 单独,或者它不取决于开发人员和许多流行的 java 库也有可能导致 Hash Collision 的类?

    • 不,可能会发生碰撞,因为它们是由数学概率决定的,在这种情况下,生日悖论是解释这一点的最佳方式。

    当 Hash Collision 发生时,是否会出现任何问题或意外情况?我的意思是我们有什么理由应该避免哈希冲突?

    • 不,Java中的String类是非常完善的类,你不需要搜索太多就可以找到冲突(检查这个字符串“Aa”和“BB”的hascode->都与2112发生冲突)

    总结一下: 哈希码冲突是无害的,您是否知道这是为了什么以及为什么 不 与用于证明相等性的 id 相同

    【讨论】:

    • 对不起,我对这部分的Java知识很差,但我真的不明白这一点:Java中的String类是非常发达的类,你不需要搜索太多就可以找到冲突(检查这个字符串“Aa”和“BB”的hascode - >都与2112发生冲突)如果你能解释一下吗?
    • 我的意思是即使在非常完善的类上也可能发生冲突...... String 类就是一个例子......它的 2 个实例会产生哈希冲突,这并不意味着该类是否损坏写的很好……
    【解决方案4】:

    Hash Collision 到底是什么——它是一种特性,还是一种普遍现象 哪些是错误的,但最好避免?

    两者都不...两者都...这是一种普遍现象,但不要误以为是,最好避免。

    究竟是什么导致了哈希冲突——自定义的错误定义 类的 hashCode() 方法,或者离开 equals() 方法 在未完全覆盖 hashCode() 方法时未覆盖 单独,或者它不取决于开发人员和许多流行的 java 库也有可能导致 Hash Collision 的类?

    如果你的 hashCode() 方法设计不当,你可能会产生太多的冲突,让你的 equals 方法未被覆盖不应该直接影响冲突的数量,许多流行的 java 库都有可能导致冲突的类(实际上几乎所有类)。

    当 Hash Collision 发生时,是否会出现任何错误或意外情况?一世 意思是我们有什么理由应该避免哈希冲突?

    性能下降,这是避免它们的原因,但程序应该继续工作。

    Java 是否生成或至少尝试生成唯一的 hashCode 对象启动期间的类​​?如果不是,依赖Java是否正确 单独确保我的程序不会遇到哈希冲突 JRE课程?如果不正确,那么如何避免哈希冲突 以 String 等 final 类为键的 hashmap?

    Java 在对象初始化期间不会尝试生成唯一的哈希码,但它具有 hashCode() 和 equals() 的默认实现。默认实现可以知道两个对象引用是否指向同一个实例,并且不依赖于对象的内容(字段值)。因此,String 类有自己的实现。

    【讨论】:

      猜你喜欢
      • 2014-09-11
      • 2021-11-13
      • 2018-05-23
      • 1970-01-01
      • 2015-11-14
      • 1970-01-01
      • 2011-01-21
      • 2018-09-25
      • 2014-10-28
      相关资源
      最近更新 更多