【发布时间】:2017-02-14 17:07:05
【问题描述】:
虽然我知道两个不同的字符串可以返回相同的哈希码,但我一直无法找到关于两个不同长度的任何信息。这是否可能,如果可以,将不胜感激。这是使用 java hashcode 函数,以防万一发生任何变化。
【问题讨论】:
虽然我知道两个不同的字符串可以返回相同的哈希码,但我一直无法找到关于两个不同长度的任何信息。这是否可能,如果可以,将不胜感激。这是使用 java hashcode 函数,以防万一发生任何变化。
【问题讨论】:
哈希码分布在int 的空间中。对于int,只有2^32 = ~4 billion 可能的值。可能的字符串远不止这个数量,因此根据鸽巢原理,必须存在多个具有相同哈希码的字符串。
但是,这并不能证明不同长度的字符串可能具有相同的哈希码,如下所述。 Java 使用公式s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 对字符串进行哈希处理。知道了这一点,就很容易构造出具有相同哈希码的不同长度的字符串:
让String s1 = "\001!"; 和String s2 = "@";。然后s1.length() != s2.length() 但s1.hashCode() == '\001' * 31 + '!' == 1 * 31 + 33 == 64 == s2.hashCode() == '@' == 64。
但是,让我再说一遍,int 有超过 40 亿 个可能的值,所以你的碰撞概率很低,虽然没有你想象的那么低,因为Birthday Paradox,这使您在大约 77K 散列后有大约 50% 的机会发生冲突(假设散列是随机分布的,这实际上取决于您的数据 - 如果您主要处理长度非常小的字符串,您将遇到更频繁的冲突)。但是,每个使用散列处理的数据结构都必须处理冲突(例如,一种常见的方法是在每个散列位置使用链表),或者处理数据丢失(例如在布隆过滤器中)。
【讨论】:
是的,这可能发生。
一些相当琐碎的例子:
"foo"、"\0foo"、"\0\0foo" 等都具有相同的哈希码。new String(new char[] { 12, 13 }) 与单字符new String(new char[] { 12 * 31 + 13 }) 具有相同的哈希码(我任意选择了12 和13;对于任何其他值,只要因为12 * 31 + 13 模拟保持在两字节无符号整数范围内)。但这些只是一些易于构建的示例。还有很多字符串对恰好具有相同的哈希码,尽管它们之间没有明显的关系。
【讨论】: