两个不同长度的字符串可以具有相同的哈希码吗?

时间:2016-10-06 04:53:15

标签: java string hashcode

虽然我知道两个不同的字符串可以返回相同的哈希码,但我无法找到任何关于两个不同长度的字符串。这是可能的,如果是这样的话,将会受到赞赏。这是使用java哈希码函数,以防任何变化。

2 个答案:

答案 0 :(得分:3)

Hashcodes分布在int的空间内。 2^32 = ~4 billion只有int个可能的值。有很多可能的字符串,所以根据鸽子原则,必须存在多个具有相同哈希码的字符串。

但是,这并不能证明不同长度的字符串可能具有相同的哈希码,如下所述。 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的可能值超过4 亿,所以你的碰撞概率很低,虽然没有你想象的那么低,因为Birthday Paradox,它给你在大约77K哈希后有大约50%的碰撞几率(假设哈希是随机分布的,这实际上取决于你的数据 - 如果你主要处理非常小的长度字符串你会有更频繁的碰撞)。然而,使用散列处理的每个数据结构必须处理冲突(例如,常见的方式是在每个散列位置使用链表),或处理数据丢失(例如在布隆过滤器中)。

答案 1 :(得分:2)

是的,这可能发生。

一些相当简单的例子:

  • 初始零值字符不会影响哈希码,因此(例如)"foo""\0foo""\0\0foo"等都具有相同的哈希码
  • 在添加下一个字符之前,每个字符乘以31;所以(例如)双字符串new String(new char[] { 12, 13 })具有与单字符new String(new char[] { 12 * 31 + 13 })相同的哈希码(我选择1213的位置相同;相同适用于任何其他值,只要12 * 31 + 13模拟值保持在两字节无符号整数范围内。)

但这些只是一些易于构建的例子。尽管它们之间没有明显的关系,但也有很多字符串恰好碰巧具有相同的哈希码。