为什么dict在这么多操作中遇到最坏情况O(n)?

时间:2011-02-01 01:09:08

标签: python

dict如何实现它具有线性时间查找冲突?我假设它是作为由列表支持的哈希表实现的。我认为对于各种操作,更好的实现将是O(log(n)),而使用树来代替表。幕后是否会发生一些魔法,以尽可能长时间地保持恒定时间查找的存在?

顺便说一句,我的来源是:

http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=python+complexity

5 个答案:

答案 0 :(得分:9)

对于大多数操作,Dict是O(1),除了触摸所有元素的操作,例如迭代和复制(在这种情况下,它显然是O(n))。

请参阅:http://wiki.python.org/moin/TimeComplexity

它有O(n)最坏的情况,因为你总是可以设想一个所有键具有相同哈希值的病态示例。

答案 1 :(得分:2)

选择一个实现而不是另一个实现的重点不一定是upper-bound,而是预期的amortized performance。虽然不同的算法可以具有退化情况,但它通常“比实际上更好”而不是使用具有可证明的较低上限的方法。但是,在某些情况下,必须设计结构以防止病态的不良输入。

此外,一些语言/库 - 不确定Python - 实际上改变了底层实现,例如当项目数超过低n时。这会影响摊销的绩效(在某些情况下),但不一定影响big O

最后:“这取决于”。

快乐的编码。

答案 2 :(得分:1)

考虑银河系中最好的哈希函数。有一天你可能会带着一个值列表向上走,这些值列表的最佳散列函数值恰好相同。如果你把它们放在一个字典中,系统别无选择,只能进行线性搜索。

使用平衡树会将最坏情况下的时间保持在O(log n),但维护成本相当高。通常,哈希表的表现非常好。

答案 3 :(得分:1)

  

我认为对于各种操作,更好的实现将是O(log(n)),而使用树来代替表。

树和哈希表具有非常不同的要求和性能特征。

  • 树木需要有序的类型。
  • 树需要执行顺序比较才能找到对象。对于某些对象,如字符串,这可以防止一些重要的优化:您总是需要执行字符串比较,这非常昂贵。这使得常数因子O(log n)相当高。
  • 哈希表需要一个哈希类型,并且您可以测试相等性,但它们不需要有序类型。
  • 可以显着优化对相等性的测试。如果两个字符串被中断,你可以通过比较它们的指针来测试它们在O(1)中是否相等,而不是通过比较整个字符串来比较O(n)。这是大量优化:在每个foo.bar查找中,foo.__dict__["bar"]被转换为"bar"__dict__是一个实习字符串。
  • 哈希表在最坏的情况下是O(n),但检查导致最坏情况的原因:非常糟糕的哈希表实现(例如,您只有一个桶),或者总是返回相同的哈希函数值。当你有一个合适的哈希函数和一个适当的存储算法时,查找非常便宜 - 通常接近恒定时间。

树木确实具有显着优势:

  • 他们往往具有较低的内存要求,因为他们不必预先分配存储桶。最小的树可能是12个字节(节点指针和两个子指针),其中哈希表往往是128个字节或更多 - 我系统上的sys.getsizeof({})是136.
  • 他们允许有序遍历;能够在有序集中迭代[a,b)是非常有用的,哈希表不允许这样做。

我认为Python没有标准的二叉树容器是一个缺陷,但是对于Python核心所需的性能特征,如{{1}}查找,哈希表确实更有意义。

答案 4 :(得分:0)

有关实际使用的哈希函数和冲突解决策略的可靠信息来源包括源文件dictobject.c中的注释和整个文件dictnotes.txt