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感兴趣。 如果您希望它按排序顺序,显然这不会在线性时间内发生。否则,您可以调用nlargest
和 t=n
以在线性时间内对列表进行比较排序。如果您只想要 any 顺序中的 t
最大元素,则可以使用 quickselect 在 O(n) 中完成。不过,heapq.nlargest
不使用快速选择;它使用基于堆的算法按排序顺序提供项目。
只是一个一般说明:声称需要时间 O(t + n) 本身让我很警惕,因为这只是 O(n)。这在技术上并不错误,但这样表达有点奇怪
【参考方案1】:
在这种情况下,扬声器是错误的。实际费用为O(n * log(t))
。仅在可迭代的第一个 t
元素上调用 Heapify。那是O(t)
,但如果t
比n
小得多,则无关紧要。然后所有剩余的元素都通过heappushpop
一次一个地添加到这个“小堆”中。每次调用heappushpop
需要O(log(t))
时间。堆的长度始终保持t
。最后,堆被排序,花费O(t * log(t))
,但如果t
比n
小得多,这也是微不足道的。
理论的乐趣 ;-)
有一些相当简单的方法可以在预期的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 的时间复杂度是多少?的主要内容,如果未能解决你的问题,请参考以下文章