heapq.nlargest 的时间复杂度是多少?

Posted

技术标签:

【中文标题】heapq.nlargest 的时间复杂度是多少?【英文标题】:What is the time complexity of heapq.nlargest? 【发布时间】:2014-05-27 03:41:03 【问题描述】:

我正在查看this pycon talk, 34:30,演讲者说可以在O(t + n) 中获取n 元素列表中最大的t 元素。

这怎么可能?我的理解是创建堆会是O(n),但是nlargest本身的复杂度是多少,是O(n + t)还是O(t)(实际算法是什么)?

【问题讨论】:

你可能对the source code感兴趣。 如果您希望它按排序顺序,显然这不会在线性时间内发生。否则,您可以调用 nlargestt=n 以在线性时间内对列表进行比较排序。如果您只想要 any 顺序中的 t 最大元素,则可以使用 quickselect 在 O(n) 中完成。不过,heapq.nlargest 不使用快速选择;它使用基于堆的算法按排序顺序提供项目。 只是一个一般说明:声称需要时间 O(t + n) 本身让我很警惕,因为这只是 O(n)。这在技术上并不错误,但这样表达有点奇怪 【参考方案1】:

在这种情况下,扬声器是错误的。实际费用为O(n * log(t))。仅在可迭代的第一个 t 元素上调用 Heapify。那是O(t),但如果tn 小得多,则无关紧要。然后所有剩余的元素都通过heappushpop 一次一个地添加到这个“小堆”中。每次调用heappushpop 需要O(log(t)) 时间。堆的长度始终保持t。最后,堆被排序,花费O(t * log(t)),但如果tn 小得多,这也是微不足道的。

理论的乐趣 ;-)

有一些相当简单的方法可以在预期的O(n) 时间内找到第 t 大元素;例如,see here。在最坏的情况下O(n) 时间有更难的方法。然后,在另一个输入中,您可以输出 t 元素 >= 第 t 个最大的元素(在重复的情况下会有繁琐的复杂性)。所以整个工作可以O(n)时间完成。

但这些方式也需要O(n) 内存。 Python 不使用它们。实际实现的一个优点是,最坏情况下的“额外”内存负担是O(t),例如,当输入是产生大量值的生成器时,这可能非常重要。

【讨论】:

这很有意义;我真的希望O(t + n) 是对的,我想我会学习一些新的堆魔法:) 查看刚才编辑的 O(n) 方法 - 但它与堆无关,唉。 有趣的事实:实际上,您可以在 O(n) 中对数组进行堆集,并在每个查询的 O(k) 时间内获取结果堆的 top-k。虽然它非常重要,但 heapq 模块没有实现它。 (它也可能有巨大的常数因素使其在实践中不可行) @NiklasB。我在哪里可以了解这个O(k) 算法?即使不平凡,我也非常感兴趣! @foo ***.com/questions/22574580/…【参考方案2】:

对于 Heapq t 最大或 t 最小,时间复杂度将为O(nlog(t))

Heapq 将为前 t 个元素构建堆,然后它会通过从堆中推送和弹出元素来迭代剩余的元素(维护堆中的 t 个元素)。

    为前 t 个元素构建堆将完成tlog(t) 对于推送和弹出,其余元素将在 (n-t)log(t) 整体时间复杂度为nlog(t)

【讨论】:

【参考方案3】:

实际上是 O(n+tlog(n)),因为 heapify 需要 O(n) 并且对于每个最大或最小的元素需要 O(log(n))。所以对于 t 最大/最小它需要 tlog(n)。因此时间复杂度将是 O(n+t*log(n))

【讨论】:

以上是关于heapq.nlargest 的时间复杂度是多少?的主要内容,如果未能解决你的问题,请参考以下文章

python中使用heapq查看最大与最小的N个元素列表

python3-开发进阶 heapq模块(如何查找最大或最小的N个元素)

python之使用heapq()函数计算列表中数值大小

heapq

Python实用黑科技——找出最大/最小的n个元素

怎样从一个集合中获得最大或者最小的 N 个元素列表?