在查看source code of java.lang.String of openjdk-1.6时,我看到String.hashCode()使用31作为素数并计算
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
现在我看这个的原因是我想到的问题是,比较String.equals中的hashCodes会使String.equals显着加快。但现在看看hashCode,我想到了以下问题:
答案 0 :(得分:8)
不是更大的主要帮助更好地避免碰撞,至少对于短串,看到例如“BC”具有与“Ab”相同的哈希(因为ascii字母存在于区域65-122,不会'比这项工作更好的素数)?
String中的每个字符可以采用65536个值(2 ^ 16)。因此,1或2个字符的字符串集合大于int
的数量,并且任何哈希码计算方法都会产生1或2个字符长的字符串的冲突(我认为这符合短字符串)。
如果限制字符集,可以找到减少碰撞次数的散列函数(见下文)。
请注意,良好的哈希还必须提供良好的输出分布。一个评论埋没in this code倡导者使用33并给出以下理由(强调我的):
如果比较变体的chi ^ 2值[...],则数字33甚至不具有最佳值。但是33号和其他一些同样好的数字如17,31,63,127和129对于大量可能的乘数中的剩余数字仍然有很大的优势:它们的乘法运算可以用更快的运算代替只需一个班次加上一个加法或减法操作。而因为哈希函数必须分配好并且必须非常快速地计算,所以应该首选这些数字。
现在这些公式是前一段时间设计的。即使它现在看起来不理想,也不可能改变实现,因为它记录在String类的合同中。
是否有意识地决定使用31作为素数,或者只使用一些随机因素,因为它很常见?
Why does Java's hashCode() in String use 31 as a multiplier?
给定固定的字符串长度,哈希冲突的可能性有多大?
假设每个可能的int值与hashcode函数的结果具有相同的概率,则碰撞概率为2 ^ 32中的1。
String.equals是否有充分的理由不将hashCodes作为附加快捷方式进行比较?
Why does the equals method in String not use hash?
假设我们有两个具有相同内容但具有不同实例的字符串:有没有办法断言相等而不实际比较内容?
对字符串没有任何约束,没有。您可以实习字符串,然后检查引用相等性(==
),但如果涉及许多字符串,那可能效率低下。
我们需要多少限制字符串空间才能拥有这样的哈希函数?
如果你只允许使用小写字母(26个字符),你可以设计一个哈希函数,为任何长度为0到6个字符(含)(sum(i=0..6) (26^i) = 3.10^8
)的字符串生成唯一的哈希值。