哈希冲突到底是什么

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

  1. 哈希冲突到底是什么 - 它是一种功能,还是一种常见现象,它被错误地完成但最好避免?
  2. 究竟是什么原因导致哈希冲突 - 自定义类方法的错误定义,或者使方法未被覆盖,而不完全覆盖方法,或者它不是由开发人员决定的,许多流行的java库也有可能导致哈希冲突的类?hashCode()equals()hashCode()
  3. 发生哈希冲突时,是否有任何错误或意外?我的意思是,我们有什么理由应该避免哈希冲突吗?
  4. Java在对象启动期间是否生成或至少尝试为每个类生成唯一的哈希码?如果不是,那么仅依靠Java来确保我的程序不会遇到JRE类的哈希冲突是正确的吗?如果不正确,那么如何避免使用String作为键等最终类的哈希映射的哈希冲突?

如果你能分享你对其中一个或所有问题的答案,我会很高兴。


答案 1

哈希冲突到底是什么 - 它是一种功能,还是一种常见现象,它被错误地完成但最好避免?

这是一个功能。它源于哈希码的本质:从大值空间到小值空间的映射。根据设计和意图,将会有碰撞。

究竟是什么原因导致哈希冲突 - 自定义类的hashCode()方法的错误定义,

糟糕的设计可能会使情况变得更糟,但它在这个概念中是普遍存在的。

或者让 equals() 方法保持未重写状态,同时不完全重写 hashCode() 方法,

哈哈

或者它不是由开发人员决定的,许多流行的java库也有可能导致哈希冲突的类?

这真的没有道理。哈希值迟早会发生冲突,而糟糕的算法可以更快地发生冲突。仅此而已。

发生哈希冲突时,是否有任何错误或意外?

如果哈希表编写得当,则不会。哈希冲突仅意味着哈希代码不是唯一的,这使您进入调用 ,并且重复项越多,性能就越差。equals()

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

你必须权衡计算的难易程度和价值的传播。没有单一的黑白答案。

Java在对象启动期间是否生成或至少尝试为每个类生成唯一的 hasCode?

“唯一哈希代码”在术语上是矛盾的。

如果不是,那么仅依靠Java来确保我的程序不会遇到JRE类的哈希冲突是正确的吗?如果不正确,那么如何避免使用String作为键等最终类的哈希映射的哈希冲突?

这个问题毫无意义。如果你正在使用,你对哈希算法没有任何选择,而且你也正在使用一个类,其哈希代码已经被专家奴役了二十年或更长时间。String


答案 2

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

但是如何做到呢?使用哈希!!

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

以及如何处理碰撞?在我们上面讨论的这个例子中,很难分隔碰撞,因为数学计算具有一定的可能性。我们可以找到一个更复杂,更好的哈希函数,但不能肯定地说我们消除了冲突。我们应该努力找到一个更好的哈希函数来减少哈希冲突。由于哈希冲突增加了时间成本,因此我们使用哈希来查找某些内容。

简单地说,有两种方法可以处理哈希冲突。链接列表是一种更直接的方法,例如:如果上面的两个数字在hash_function后获得相同的值,我们从这个值存储桶创建一个链接列表,并且所有相同的值都放置值的链接列表。另一种方法是,只需为后面的数字找到一个新位置即可。例如,如果数字 1000005 在 5 中占据了位置,而当2000005得到值 5 时,它不能位于位置 5,然后它继续找到一个空位置。

对于最后一个问题:Java在对象启动期间是否生成或至少尝试为每个类生成唯一的哈希码?

Object 的哈希码通常是通过将对象的内部地址转换为整数来实现的。因此,如果您使用对象的哈希码(),则可以认为不同的对象具有不同的哈希码。