字典和Hashtables空间复杂度[重复]

问题描述 投票:4回答:1

这个问题在这里已有答案:

我对字典和哈希表有一些混淆,我想澄清一下。假设我有当前的字典和当前python运行的哈希的当前输出。

Dict = dict()
print(hash('a'))
print(hash('b'))
print(hash('c'))
Dict['a'] = 1
Dict['b'] = 2
Dict['c'] = 3
print(Dict)

有输出

1714333803
1519074822
1245896149
{'a': 1, 'c': 3, 'b': 2}

所以据我所知,哈希表只是一个数组,其中哈希是哈希表的索引。例如,'a'的散列值为1714333803,因此我的散列表索引1714333803的值为'a'。所以我混淆了哈希表有多少索引以及哈希函数如何产生答案?它是否使用模数并具有固定的索引范围?因为字典的给定打印输出{'a': 1, 'c': 3, 'b': 2},但假设尽管它输出了它是正确的,字典实际上是至少1714333803索引的数组,因为这似乎有点过分包含3个元素,更不用说有多少了它是浪费空间。同样对于哈希表,索引中没有值的是什么,null?

python dictionary hashtable space
1个回答
6
投票

dict的实际大小取决于实现,但在你的情况下,它可能是8.所以,这是如何工作的?

dict(或一般的哈希映射)的工作原理是为每个键计算数值哈希。在你的情况下,那是hash("a") == 1714333803,例如。现在,哈希不直接用作索引。相反,它被映射到字典的大小。

一个简单的方法是模数(%)。假设您的dict大小为8。然后hash("a") % 8 == 1714333803 % 8 == 3。所以你的物品实际上位于第4位。通过构造查找算法,任何项都不能在数组外部具有索引。

这里有一些更复杂的东西,比如哈希冲突。例如,如果另一个项目具有哈希值98499,那么它也会映射到3。在这种情况下,存在选择不同索引的冲突解决策略。他们大多尝试在大步中均匀地行走阵列。

那么,为什么你的大小为8的dict?因为那是default size in python。一旦你的dict太小,它必须调整大小。与数组相比,这是在dict实际上已经完成之前完成的 - 即在two thirds filling。这样做是为了减少哈希冲突 - 如果你的dict满99%,几乎可以保证碰撞。对于8号大小的dict,你必须在调整大小之前输入5-6个项目,即doubles its capacity到16。


请注意,CPython 3.6+PyPy (for a long time)使用two-stage data structure作为dict。第一阶段是哈希表,但第二阶段不是。这将分离键映射(第一阶段)和数据存储(第二阶段)。稀疏的第一阶段为紧密包装的第二阶段提供索引:

# based on Raymond Hettingers mail on python-dev
# the key mapping, using a hashtable
# indices[hash(key) % length] => data index
indices =  [None, None, None, 0, None, 2, 1, None]

# the data storage, packed in insertion order
# entries[index] => hash(key), key, value
entries =  [[1714333803, 'a', 1],
            [1519074822, 'b', 2],
            [1245896149, 'c', 3]]

该方案在算法上对于查找(由于间接)而言更复杂,但对于迭代(直接在数据存储上)和更高的存储器效率则更少。只有索引表是稀疏的,需要加大尺寸。除非删除项目,否则数据存储与所需的完全一样大。

© www.soinside.com 2019 - 2024. All rights reserved.