Java中用于文本字符串的64位哈希函数是什么?

rip*_*234 55 java string hash 64-bit collision

我正在寻找一个哈希函数:

  1. 哈希文本字符串很好(例如很少碰撞)
  2. 是用Java编写的,并且被广泛使用
  3. 奖励:适用于多个字段(而不是我连接它们并在连接字符串上应用哈希)
  4. 额外奖励:有128位变体.
  5. 奖励:不是CPU密集型.

sfu*_*ger 64

你为什么不使用long默认的变体String.hashCode()(一些非常聪明的人肯定会努力使它变得高效 - 没有提到成千上万的开发人员眼睛已经看过这个代码)?

// adapted from String.hashCode()
public static long hash(String string) {
  long h = 1125899906842597L; // prime
  int len = string.length();

  for (int i = 0; i < len; i++) {
    h = 31*h + string.charAt(i);
  }
  return h;
}
Run Code Online (Sandbox Code Playgroud)

如果您正在寻找更多位,您可以使用BigInteger 编辑:

正如我在对@brianegge的回答的评论中提到的那样,对于超过32位的哈希,并且对于超过64位的哈希值,很可能没有多少用例:

我可以想象一个巨大的哈希表分布在几十台服务器上,可能存储了数百亿的映射.对于这种情况,@ brianegge在这里仍然有一个有效点:32位允许2 ^ 32(约43亿)个不同的散列键.假设一个强大的算法,你应该仍然有很少的碰撞.使用64位(18,446,744,073亿个不同的键),无论您需要什么样的疯狂场景,都可以保存.考虑使用128位密钥的用例(340,282,366,920,938,463,463,374,607,431亿可能的密钥)几乎是不可能的.

要合并多个字段的哈希值,只需将一个XOR与一个素数相乘并添加它们:

long hash = MyHash.hash(string1) * 31 + MyHash.hash(string2);
Run Code Online (Sandbox Code Playgroud)

小素数在那里以避免切换值的相等哈希码,即{'foo','bar'}和{'bar','foo'}不相等并且应该具有不同的哈希码.如果两个值相等,则XOR为坏,因为它返回0.因此,{'foo','foo'}和{'bar','bar'}将具有相同的哈希码.

  • String.hashCode仅适用于快速计算(`h*31`优化为`(i << 5) - i`),但它对于避免文本哈希冲突(字符串"FB"和"Ea")很差碰撞).由于这个64位散列是相同的,它具有基本相同的弱点. (3认同)
  • 关于 64 位和 128 位密钥的用例:也许您想要一个哈希作为字符串的唯一签名,以避免完全存储字符串内容。在这里,您最好 (a) 使用加密强度散列,并且 (b) 在选择散列大小时不要忘记“生日问题”(询问维基百科)。即使是“好”的 64 位散列,也必须假设具有较低的 # 位“安全性”(比如 32)——因此与 BP 一起,即使对于超过 100,000 个字符串的集合,它也开始作为唯一签名看起来不可靠。git 使用 160 位 SHA-1 是有原因的 :-) (2认同)

Sco*_*rey 5

今天的答案(2018)。哈希。

它将比这里的大多数答案快得多,并且质量明显高于所有答案。

Guava 库有一个:https : //google.github.io/guava/releases/23.0/api/docs/com/google/common/hash/Hashing.html#sipHash24--