【问题标题】:Python heapify() time complexityPython heapify() 时间复杂度
【发布时间】:2019-01-15 01:40:37
【问题描述】:
def heapify(A):
    for root in xrange(len(A)//2-1, -1, -1):
        rootVal = A[root]
        child = 2*root+1
        while child < len(A):
            if child+1 < len(A) and A[child] > A[child+1]:
                child += 1
            if rootVal <= A[child]:
                break
            A[child], A[(child-1)//2] = A[(child-1)//2], A[child]
            child = child *2 + 1

这是 python heapq.heapify() 的类似实现。在文档中说这个函数在 O(n) 中运行。但看起来对于 n/2 个元素,它执行 log(n) 操作。为什么是 O(n)?

【问题讨论】:

标签: python python-3.x python-2.7 heap heapq


【解决方案1】:

这需要更仔细的分析,比如你会find here。基本的见解是只有堆的根实际上有深度log2(len(a))。在叶子上方的节点处 - 一半的节点存在 - 在第一次内循环迭代中命中叶子。

“精确”推导

挥手,当算法查看具有N 元素的子树的根节点时,每个子树中大约有N/2 元素,然后需要与log(N) 成比例的工作来合并根和那些子堆成一个堆。所以T(N)所需的总时间约为

T(N) = 2*T(N/2) + O(log(N))

这是一个不常见的复发。不过Akra–Bazzi method 可以用来推断它是O(N)

我认为更多信息,当然也更令人满意,是从头开始得出一个精确的解决方案。为此,我将只讨论完整的二叉树:在每个级别上都尽可能完整。然后总共有2**N - 1 个元素,所有子树也是完全二叉树。这避免了当事情不完全平衡时如何进行的大量毫无意义的细节。

当我们查看具有2**k - 1 元素的子树时,它的两个子树中的每一个都恰好有2**(k-1) - 1 元素,并且有k 级别。例如,对于一棵有 7 个元素的树,根有 1 个元素,第二层有 2 个元素,第三层有 4 个。子树堆积后,根必须移动到位,将其向下移动 0、1 或 2 级。这需要在级别 0 和 1 之间进行比较,也可能在级别 1 和 2 之间进行比较(如果根需要向下移动),但仅此而已:所需的工作与k-1 成正比。总而言之,

T(2**k - 1) = 2 * T(2**(k-1) - 1) + (k - 1)*C

对于一些常量C 限制了比较相邻级别的元素的最坏情况。

T(1) 呢?那是免费的!一棵只有 1 个元素的树已经是一个堆 - 没有什么可做的。

T(1) = 0

在这些树叶之上一层,树木有 3 个元素。将最小的(对于最小堆;最大的对于最大堆)移动到顶部的成本(不超过)C

T(3) = C

上一层,树有 7 个元素。 T(3) 堆积每个子树,然后不超过 2*C 将根移动到位:

T(7) = 2*C + 2*C = 4*C

以同样的方式继续:

T(15) = 2* 4*C + 3*C = 11*C
T(31) = 2*11*C + 4*C = 26*C
T(63) = 2*26*C + 5*C = 57*C
...
T(2**k - 1) = (2**k - k - 1)*C

最后一行是对一般形式的猜测。您可以验证它之前的所有特定行是否“有效”,然后通过归纳来证明它很简单。

那么,N = 2**k - 1

T(N) = (N - log2(N+1)) * C

这表明T(N)C*N 为界,O(N) 也是如此。

【讨论】:

  • 我不明白。这并不能解释为什么 heapify() 需要 O(log(N))。 TH(n) = c, 如果 n=1 最坏的情况,如果从不根,则最大:TH(n) = c + ? * TH( ? ) 递归表达式怎么写?
  • 已经给出了详细分析的链接。它不使用递归公式,也没有必要。并且声称不是 heapify 需要 O(log(N)) 时间,而是需要 O(N) 时间。如果您有重点问题,请考虑打开其他问题。
  • @user3742309,请参阅编辑以获取从头开始的完整推导。
猜你喜欢
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 2016-02-13
  • 2012-08-14
  • 2020-03-25
  • 2018-11-20
相关资源
最近更新 更多