有人能解释一下这个哈希函数背后的逻辑吗?。
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
我将key.hashCode()
传递给此函数,该函数为我提供了哈希值。根据此值和数组大小,我计算数组的索引。我只是不理解这个方法中使用的运算符。
^
运算符在此上下文中执行了什么操作。它检查!= 传递给此哈希函数的key.hashCode()
为79847235
。任何人都可以解释内部发生的事情以返回最终的哈希值。
答案 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中指定的位数。从左边填充零。从右侧偏移的数字被丢弃。所以这种转变并不尊重这个标志。
那么这个功能是做什么的......
修改:注意到已在接受的答案中对此进行了广泛分析: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))
(由于我们除以较小的数字,因此更大)。<登记/>
现在我们在19493
和exclusive OR
上预先形成76
例如,19493
为1^0
1
是1^1
如果我们想要包括AND,我们必须使用包含OR,即|
因此0
是1|1
1
是1|0
等
0
是1001100
的二进制表示
76
是100110000100101
的二进制表示
19493
操作如下所示:
exclusive OR
(二进制000000001001100
)
76
(二进制100110000100101
)
19493
---------------
(我们的结果:100110001101001
)
我们的第一行差不多完成了:
我们得到了这个:
19561
至:
h ^= (h >>> 20) ^ (h >>> 12);
这与以下相同:
h ^= 19561
填写h = h^19561
h
的值{
1}}
79847235
是79847235^19561
79827754
请务必记住 h = 79827754
的新值现在 h
下一行:
79827754
return h ^ (h >>> 7) ^ (h >>> 4);
为h>>>7
,返回Math.floor(79827754/Math.pow(2,7))
623654
为h>>>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)
9
为17^2
(大于我们的参数17)