什么是实现__hash__()的正确且好的方法
我说的是一个函数,它返回一个哈希码,然后用来将对象插入哈希表,也就是字典。
由于__hash__()返回一个整数,并用于将对象“打包”到哈希表中,因此我假设返回的整数的值对于公共数据应该是均匀分布的(以最小化冲突)。获得这样的值的好做法是什么?碰撞是一个问题吗?在我的例子中,我有一个小类,它充当容器类,包含一些整数、一些浮点数和一个字符串。
发布于 2010-05-26 06:59:52
实现__hash__()的一种简单、正确的方法是使用密钥元组。它不会像专门的散列那样快,但是如果你需要它,那么你可能应该用C实现这个类型。
下面是一个使用键进行散列和相等的示例:
class A:
def __key(self):
return (self.attr_a, self.attr_b, self.attr_c)
def __hash__(self):
return hash(self.__key())
def __eq__(self, other):
if isinstance(other, A):
return self.__key() == other.__key()
return NotImplemented此外,documentation of __hash__还提供了更多信息,这些信息在某些特定情况下可能很有价值。
发布于 2010-05-26 09:05:53
微软研究院的Paul Larson研究了各种各样的散列函数。他告诉我
for c in some_string:
hash = 101 * hash + ord(c)令人惊讶的是,它对各种各样的字符串都工作得很好。我发现类似的多项式技术可以很好地计算不同子字段的散列。
发布于 2010-05-26 08:58:40
我可以试着回答你问题的第二部分。
冲突可能不是由散列代码本身引起的,而是由将散列代码映射到集合中的索引引起的。例如,您的哈希函数可以返回从1到10000的随机值,但是如果您的哈希表只有32个条目,则在插入时会发生冲突。
此外,我认为冲突将由集合在内部解决,并且有许多方法可以解决冲突。最简单(也是最糟糕)的方法是,给出一个要在索引i处插入的条目,将i加1,直到找到一个空点并在那里插入。然后,检索也以同样的方式工作。这会导致对某些条目的检索效率低下,因为您可能有一个条目需要遍历整个集合才能找到!
其他冲突解决方法通过在插入项以展开事物时移动哈希表中的条目来减少检索时间。这会增加插入时间,但假设您阅读的内容多于插入的内容。还有一些方法尝试将不同的冲突条目分支出来,以便条目聚集在一个特定的点上。
此外,如果您需要调整集合的大小,您将需要重新散列所有内容或使用动态散列方法。
简而言之,根据您使用的散列代码,您可能必须实现自己的冲突解决方法。如果您没有将它们存储在一个集合中,那么您可能可以使用一个散列函数,它只会在一个非常大的范围内生成散列代码。如果是这样的话,你可以确保你的容器比它需要的更大(当然越大越好),这取决于你的内存问题。
如果你更感兴趣,这里有一些链接:
coalesced hashing on wikipedia
维基百科也有各种冲突解决方法的summary:
此外,塔普的"File Organization And Processing“广泛地涵盖了许多冲突解决方法。这是哈希算法的一个很好的参考。
https://stackoverflow.com/questions/2909106
复制相似问题