Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么dict有这么多操作的最坏情况O(n)?_Python - Fatal编程技术网

Python 为什么dict有这么多操作的最坏情况O(n)?

Python 为什么dict有这么多操作的最坏情况O(n)?,python,Python,dict是如何实现的,它有一个线性时间查找冲突?我假设它是作为列表支持的哈希表实现的。我认为更好的实现是针对各种操作的O(log(n)),而是使用树来支持表。有没有什么神奇的事情发生在幕后,让固定时间的查找尽可能长 顺便说一下,我的资料来源是: 对于大多数操作来说,Dict是O(1),除了涉及所有元素的操作,例如迭代和复制(在这种情况下,显然是O(n)) 见: 最坏的情况是O(n),因为你总是可以设计一个病态的例子,其中所有键都具有相同的哈希值。考虑银河系中最好的哈希函数。总有一天,您可能会看到

dict是如何实现的,它有一个线性时间查找冲突?我假设它是作为列表支持的哈希表实现的。我认为更好的实现是针对各种操作的O(log(n)),而是使用树来支持表。有没有什么神奇的事情发生在幕后,让固定时间的查找尽可能长

顺便说一下,我的资料来源是:

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

见:


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

考虑银河系中最好的哈希函数。总有一天,您可能会看到一列值,这些值的最佳哈希函数值恰好是相同的。如果你把它们放在dict中,系统别无选择,只能执行线性搜索

使用平衡树可以将最坏情况下的时间保持在O(logn),但维护成本相当高。通常,哈希表的性能相当好


我认为更好的实现是针对各种操作的O(log(n)),而是使用树来支持表

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

  • 树需要一个有序的类型
  • 树需要执行顺序比较才能找到对象。对于某些对象,如字符串,这会阻止一些重要的优化:您总是需要执行字符串比较,这非常昂贵。这使得O(logn)的常数因子相当高
  • 哈希表需要一个可哈希类型,您可以测试它是否相等,但它们不需要有序类型
  • 平等性测试可以显著优化。如果两个字符串被插入,您可以通过比较指针来测试它们在O(1)中是否相等,而不是通过比较整个字符串来测试它们在O(n)中是否相等。这是一个巨大的优化:在每一个被转换为
    foo.\uu dict.\uuu[“bar”]
    foo.bar
    查找中,
    “bar”
    是一个内部字符串
  • 哈希表在最坏的情况下是O(n),但请检查导致这种最坏情况的原因:非常糟糕的哈希表实现(例如,您只有一个bucket),或者总是返回相同值的坏哈希函数。当你有一个合适的散列函数和一个合适的bucketing算法时,查找是非常便宜的——通常接近常数时间
树木确实具有显著的优势:

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

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

选择一个实现到另一个的点不一定是关于,而是预期的。不同的算法可能有退化的情况——通常“在实践中”比使用具有可证明的上下限的方法更好。然而,在某些情况下,结构的设计必须防止病态的不良输入

此外,一些语言/库(对Python不太清楚)实际上更改了底层实现,例如当项目数超过低n时。这会影响摊销性能(在某些情况下),但不一定影响性能

最后,“这取决于”


愉快的编码。

关于实际使用的哈希函数和冲突解决策略的可靠信息源包括源文件中的注释和整个文件

最坏情况的复杂性不是唯一值得优化的因素。“我认为更好的实现应该是O(log(n))对于各种各样的操作,“为什么?你有没有看到这方面的基准测试?我的理解是“随机”探测实际上平均速度最快,并导致O(n)最坏的情况是。你在假设什么?你看到了什么测量结果?我认为Python Dict使用32位键,这意味着你需要2**31或接近6200000000000000的键,然后才能预期一次冲突(不包括那些实现
\uuuuuuu散列\uuuuuu
非常糟糕的对象,但我宁愿将其视为一个bug)。所以冲突实际上没有实际意义,花在优化上的时间是浪费时间的。@Jochen,我认为你对哈希函数有不切实际的期望。一个在耗尽存储桶之前让你发生冲突的函数并不是很糟糕,它实际上很常见。看看在你有一个b之前你能遇到多少人第一天冲突,它肯定不是365。你可以拥有完美的哈希函数,但前提是你事先理解了数据。给定一个通用哈希函数,如果你知道算法,你可以只使用两个条目创建冲突。@Jochen:当然它们有冲突;哈希表通常没有2^32个存储桶。(另外,2^31只是2147483648,而不是6200000000000000——你完全忘记了生日问题。)回答得好。记住这是一个上限很重要,即使这个上限明显更好。不幸的是,摊销性能通常被视为复杂性。