散列函数 会把一个很大的输入空间映射到一个较小的输出空间。可以用散列函数把大输入空间中的键转换为小输出空间中的整数索引。

因为可能的输出空间比可能的输入空间小,散列函数实际上是一个多对一的映射,也就是说,不同的输入可能会被映射到相同的输出。如果两个输入被映射到同一个输出,我们就说发生了碰撞。一个优秀的散列函数会产生一个均匀分布,也就是说,每个输出出现的可能性都相同,从而最小化产生碰撞的可能性。

设计一个优秀的散列函数是非常具有挑战性的。问题在于如何将具有预期分布的输入映射到均匀分布的输出上。

基础思想是用一个散列桶列表来表示intDict类的实例,每个桶是一个键值对列表。由于每个通都是一个列表,我们可以将产生碰撞的值都存储到这个列表中。

散列表的工作方式如下:实例变量buckets被初始化为一个列表,包含numBuckets个空列表。如果要存储或者查找键为dictKey的元素,我们使用散列函数%把dictKey转换成一个整数,然后用它索引关联到dictKey的散列桶。接着线性搜索这个桶(它就是一个列表)来判断是否有键为dictKey的元素。

如果我们执行的是查找操作并且有对应的元素,那就返回对应的值。如果没有对应的元素,我们返回None。如果我们执行的是存储操作并且有对应的元素,我们会替换它的值;如果没有对应的元素,我们会向这个桶中添加一个新元素。

除此之外,还有很多处理碰撞的方法,有些比使用列表更加高效。但是这可能是最简单的方法,并且在散列表足够大而且散列函数能实现近似均匀分布的情况下表现很好。

注意,__str__方法会生成字典的一个字符串形式,并且和元素添加到D中的顺序无关,而是根据键的散列结果来排序。这解释了为什么我们不应当相信字典类型对象的键的顺序。


揭开散列表的神秘面纱_散列表

以上内容来自书籍 《编程导论》美·谷泰格。