任何人都可以解释这个哈希函数背后的逻辑吗?

时间:2013-09-25 23:36:09

标签: java hash

有人能解释一下这个哈希函数背后的逻辑吗?。

static int hash(int h) {
   h ^= (h >>> 20) ^ (h >>> 12);
   return h ^ (h >>> 7) ^ (h >>> 4);
}

我将key.hashCode()传递给此函数,该函数为我提供了哈希值。根据此值和数组大小,我计算数组的索引。我只是不理解这个方法中使用的运算符。

  1. ^运算符在此上下文中执行了什么操作。它检查!=
  2. 无符号右移>>>做?。我们在Java中没有使用Unsigned int吗?
  3. 如何为此功能选择值20,12,7和4?是吗 预定义或用户定义?。
  4. 传递给此哈希函数的key.hashCode()79847235。任何人都可以解释内部发生的事情以返回最终的哈希值。

2 个答案:

答案 0 :(得分:3)

看看下面的内容:

Bitwise and Bit Shift Operators

~       Unary bitwise complement
<<      Signed left shift
>>      Signed right shift
>>>     Unsigned right shift
&       Bitwise AND
^       Bitwise exclusive OR
|       Bitwise inclusive OR

unsigned right shift相关,请参阅:unsigned right Shift '>>>' Operator in Java

另外,对于&gt;&gt;&gt;我认为:

&gt;&gt;&gt; operator将表达式1的位移位到expression2中指定的位数。从左边填充零。从右侧偏移的数字被丢弃。所以这种转变并不尊重这个标志。

那么这个功能是做什么的......

  • (h>&gt;&gt; 20)将h除以2得到20的幂。(它向右移动20次)。此外,这意味着如果您的号码是负数,则不会继续如此。
  • (h&gt;&gt;&gt; 12)将h除以2得到12的幂。(它向右移12次)...再次与负数相同。
  • 然后对两个结果进行异或,然后再用原始H进行异或。
  • 接着,更多的XORing继续计算最终的哈希值。

修改:注意到已在接受的答案中对此进行了广泛分析:Understanding strange Java hash function

答案 1 :(得分:1)

无符号右移(>>>),与带右移(>>)不同,在执行右移操作之前将负数转换为正数,确保结果返回无符号正整数。 右移,例如h >>> 20,实质上意味着返回h/Math.pow(2,20)的内联整数。
例如输入79847235,因为它是正数,都是无符号右shift和signed right shift将返回一个正整数。 79847235>>>20因此将执行:
Math.floor(79847235/Math.pow(2,20))返回76 h >>> 12的{​​{1}}的下一个向上是:79847235返回Math.floor(79847235/Math.pow(2,12))
(由于我们除以较小的数字,因此更大)。<登记/> 现在我们在19493exclusive OR上预先形成76 例如,194931^0
11^1 如果我们想要包括AND,我们必须使用包含OR,即|
因此01|1
11|0

01001100的二进制表示 76100110000100101的二进制表示 19493操作如下所示:

exclusive OR(二进制000000001001100
76(二进制100110000100101
19493
---------------(我们的结果:100110001101001

我们的第一行差不多完成了:
我们得到了这个:
19561
至:
h ^= (h >>> 20) ^ (h >>> 12);

这与以下相同:
h ^= 19561

填写h = h^19561 h的值{
1}} 7984723579847235^19561 79827754
请务必记住 h = 79827754 的新值现在 h


下一行:
79827754

return h ^ (h >>> 7) ^ (h >>> 4);h>>>7,返回Math.floor(79827754/Math.pow(2,7))
623654h>>>4,返回Math.floor(79827754/Math.pow(2,4))

现在括号不在我们的路上了:
4989234
从左到右进行预制非常重要 填写return h ^ 623654 ^ 4989234;并重新组合:
h



return (79827754 ^ 623654) ^ 4989234;是:
79827754 ^ 623654(二进制100110000100001001100101010
79827754(二进制000000010011000010000100110
623654
---------------------------(二进制100110010111001011100001100

最后我们有:
80451340

return 80451340 ^ 4989234;是:
80451340 ^ 4989234(二进制100110010111001011100001100
80451340(二进制000010011000010000100110010
4989234
---------------------------(二进制100100001111011011000111110

因此,我们的最终结果是:
76002878

随意检查我的答案,我已经仔细检查了我的工作 由于独有的按位OR的性质,很难预测散列函数的结果是大于还是小于我们的参数。 例如:
return 76002878;11^2(小于我们的参数11)
917^2(大于我们的参数17)