字典和哈希表空间复杂度

Posted

技术标签:

【中文标题】字典和哈希表空间复杂度【英文标题】:Dictionaries and Hashtables space complexity [duplicate] 【发布时间】:2016-11-03 12:08:14 【问题描述】:

我对字典和哈希表有些困惑,我想澄清一下。假设我有当前字典和当前 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?

【问题讨论】:

您可以动态调整数组的大小。但是,它必须重新计算每个键的哈希值。这个链接看起来很有趣laurentluce.com/posts/python-dictionary-implementation “没有价值的索引,null”是什么意思?没有哈希的键?或者数组中没有被填充的位置? 也可以观看此视频:youtube.com/watch?v=C4Kc8xzcA68 【参考方案1】:

dict 的实际大小取决于实现,但在您的情况下,它可能是 8。那么,这是如何工作的?

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

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

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

那么,为什么您的 dict 的大小为 8?因为那是default size in python。一旦你的dict 太小,就必须调整它的大小。与数组相比,这是在dict 实际满之前完成的——即two thirds filling。这样做是为了减少哈希冲突 - 如果您的 dict 已满 99%,则实际上可以保证发生冲突。对于大小为 8 的字典,您必须在调整大小之前输入 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]]

该方案在查找算法上更复杂(由于间接),但对于迭代(直接在数据存储上)和内存效率更高。只有索引表是稀疏的,需要超大。除非项目被删除,否则数据存储空间与需要一样大。

【讨论】:

确实,如果我理解正确的话,我认为它是使用按位实现的:hash(key) & of (size - 1),实际上是取“最后”三位(如果大小 == 8)。

以上是关于字典和哈希表空间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

数组链表与哈希

初级--03---二分复杂度哈希表和有序表

Leetcode题解——数据结构之哈希表

数据结构之时间复杂度与空间复杂度

计数排序

用哈希算法优化字典树空间结构