您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

在Python字典中计算冲突

在Python字典中计算冲突

您不能通过使用随机整数作为dict键来模拟使用对象ID作为dict键。它们具有不同的哈希函数

确实会发生碰撞。对于“ thingy”的多个值,“拥有唯一的东西意味着没有碰撞”是错误的。

您不必担心碰撞。

阅读源代码中得出的一些解释:

字典被实现为2 ** i个条目的表,其中i是整数。

格数不超过2/3。因此,对于15000个密钥,我必须为15,而2 **我为32768。

如果o是未定义类的任意实例__hash__()则hash(o)== id(o)并非正确 。由于地址可能在低阶的3或4位中为零,因此通过将地址右移4位来构造哈希。参见源文件Objects / object.c功能_Py_HashPointer

如果低序位中有很多零,那将是一个问题,因为要访问大小为2 ** i(例如32768)的表,必须对哈希值(通常比该值大得多)进行处理以使其适合,通过采用哈希值的低阶i(例如15)位,可以非常简单,快速地完成此操作。

因此, 。

但是,这不是引起恐慌的原因。哈希值的其余位将计入下一个探测的位置的计算中。需要进行第3次etc探测的可能性应该很小,尤其是因为该指令永远不会超过2/3满。计算第一个和后续探针的插槽的廉价成本可减轻多个探针的成本。

下面的代码一个简单的实验,它说明了上面的大部分讨论。假定字典达到最大大小后,它将随机访问字典。使用Python2.7.1,它可以显示2000个针对15000个对象的碰撞(占13.3%)。

无论如何,最重要的是您应该将注意力转移到其他地方。冲突不是问题,除非您已经实现了某种非常异常的方式来获取对象的内存。您应该查看如何使用dict,例如usek in d或try / except而不是d.has_key(k)。考虑将一个字典访问为d[(x, y)]而不是将两个级别访问为d[x][y]。如果您需要帮助,请提出另一个问题。

直到Python 2.7才引入旋转地址。有关全面的讨论和基准,请参阅此错误报告。基本结论仍然是恕我直言,仍然有效,可以通过“如果可以的话更新”来补充。

>>> n = 15000
>>> i = 0
>>> while 2 ** i / 1.5 < n:
...    i += 1
...
>>> print i, 2 ** i, int(2 ** i / 1.5)
15 32768 21845
>>> probe_mask = 2 ** i - 1
>>> print hex(probe_mask)
0x7fff
>>> class Foo(object):
...     pass
...
>>> olist = [Foo() for j in xrange(n)]
>>> hashes = [hash(o) for o in olist]
>>> print len(set(hashes))
15000
>>> probes = [h & probe_mask for h in hashes]
>>> print len(set(probes))
12997
>>>
python 2022/1/1 18:30:17 有198人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶