为什么tuple(set())== tuple(set())85%的时间哈希随机化启用?
给零比雷埃夫斯的另一个问题的答案 ,我们有这个
x = tuple(set([1, "a", "b", "c", "z", "f"])) y = tuple(set(["a", "b", "c", "z", "f", 1])) print(x == y)
大约85%的时间打印True
哈希随机化启用。 为什么85%?
我会假设这个问题的任何读者都阅读了两个:
-
零比雷埃夫斯的答案和
-
我对CPython词典的解释
首先要注意的是散列随机化决定于解释器启动。
每个字母的散列对于两个集合都是相同的,所以唯一可能影响的是如果发生碰撞(订单将受到影响)。
通过扣除第二个链接,我们知道这些集合的支持数组开始于8:
_ _ _ _ _ _ _ _
在第一种情况下,我们插入1
:
_ 1 _ _ _ _ _ _
然后插入其余部分:
α 1 ? ? ? ? ? ?
然后它被重新大小32:
1 can't collide with α as α is an even hash ↓ so 1 is inserted at slot 1 first ? 1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
在第二种情况下,我们插入其余的:
? β ? ? ? ? ? ?
然后尝试插入1:
Try to insert 1 here, but will ↓ be rehashed if β exists ? β ? ? ? ? ? ?
然后它会被重新表示:
Try to insert 1 here, but will be rehashed if β exists and has ↓ not rehashed somewhere else ? β ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
所以迭代次序是否不同,完全取决于β是否存在。
β的机会是这5个字母中的任何一个将散列到1模8 和散列到1模32的机会。
由于任何哈希到1的模32也哈希到1模8,所以我们想要find32个时隙中的一个,其中一个在时隙1:
5 (number of letters) / 32 (number of slots)
5/32为0.15625,所以在两套结构中有15.625%的订单机会不同 。
不是很奇怪,这正是零比雷埃夫斯所测量的。
¹在技术上这还不是很明显。 我们可以假设5个哈希值中的每一个都是唯一的,因为重新哈希,但是由于线性探测,它实际上更有可能发生“聚束”结构……但是因为我们只关注是否占用一个时隙,实际上并没有影响到我们。