Algorithm 构建堆的时间复杂度如何?
有人能解释一下堆的构建是多么复杂吗 向堆中插入一个项是O(logn),插入会重复n/2次(剩余的是叶子,不能违反heap属性)。我认为,这意味着复杂性应该是O(n logn) 换句话说,对于我们“heapify”的每个项目,到目前为止,它有可能必须对堆的每个级别(即logn级别)进行一次筛选(即筛选) 我缺少什么?如果您通过重复插入元素来构建堆,那么它将是O(n log n)。但是,通过按任意顺序插入元素,然后应用算法将它们“heapify”到正确的顺序(当然取决于堆的类型),可以更有效地创建新堆Algorithm 构建堆的时间复杂度如何?,algorithm,big-o,heap,complexity-theory,construction,Algorithm,Big O,Heap,Complexity Theory,Construction,有人能解释一下堆的构建是多么复杂吗 向堆中插入一个项是O(logn),插入会重复n/2次(剩余的是叶子,不能违反heap属性)。我认为,这意味着复杂性应该是O(n logn) 换句话说,对于我们“heapify”的每个项目,到目前为止,它有可能必须对堆的每个级别(即logn级别)进行一次筛选(即筛选) 我缺少什么?如果您通过重复插入元素来构建堆,那么它将是O(n log n)。但是,通过按任意顺序插入元素,然后应用算法将它们“heapify”到正确的顺序(当然取决于堆的类型),可以更有效地创建新
有关示例,请参见“构建堆”。在这种情况下,您基本上从树的底部开始工作,交换父节点和子节点,直到满足堆条件 你的分析是正确的。然而,它并不紧 解释为什么构建堆是一个线性操作并不容易,您应该更好地阅读它 可以看到对该算法的大量分析
主要思想是,在
build\u heap
算法中,所有元素的实际heapify
成本不是O(logn)
调用heapify
时,运行时间取决于进程终止前元素在树中向下移动的距离。换句话说,它取决于堆中元素的高度。在最坏的情况下,元素可能会一直下降到叶级别
让我们逐级统计所做的工作
在最底层,有2^(h)
节点,但我们不在其中任何节点上调用heapify
,因此工作为0。在下一级,有2^(h− 1)
节点,每个节点可能向下移动1级。在从底部开始的第三层,有2^(h− 2)
节点,每个节点可能向下移动2级
正如您所看到的,并不是所有的heapify操作都是
O(logn)
,这就是为什么您在构建堆时得到O(n)
的原因,假设您采用的是自底向上的方法
O(log(n))
小得多。程序如下:
(步骤1)第一个n/2
元素位于堆的底行h=0
,因此不需要heapify
(第2步)下一个n/22
元素位于从底部向上的第1行<代码>h=1,heapify过滤器向下1级
(步骤一)
下一个n/2i
元素从底部向上排成一行i
h=i
,heapify过滤器i
级别降低
(步骤日志(n))最后一个n/2log2(n)=1
元素从底部向上排列log(n)
h=log(n)
,heapify过滤器log(n)
级别降低
注意:在第一步之后,1/2
元素(n/2)
已经在堆中,我们甚至不需要调用heapify一次。另外,请注意,只有一个元素,即根元素,实际上会产生完整的log(n)
复杂性
理论上: 构建大小为
N
的堆的总步骤N
,可以用数学方法写出
在heighti
中,我们已经(在上面)展示了需要调用heapify的n/2i+1
元素,我们知道heapify At heighti
是O(i)
。这使得:
最后求和的解可通过取已知几何级数方程两边的导数来求出:
最后,将x=1/2
插入上述等式,得到2
。将其插入第一个方程式,得出:
因此,步骤总数的大小为O(n)我认为本主题中隐藏了几个问题:
- 如何实现
,使其在O(n)时间内运行buildHeap
- 当正确实现时,如何显示
在O(n)时间内运行buildHeap
- 为什么相同的逻辑不能使堆排序在O(n)时间而不是O(n log n)时间内运行
buildHeap
,使其在O(n)时间内运行?
通常,这些问题的答案集中在siftUp
和siftDown
之间的差异上。在siftUp
和siftDown
之间做出正确的选择对于buildHeap
获得O(n)性能至关重要,但却无能为力
(0 * n/2) + (1 * n/4) + (2 * n/8) + ... + (h * 1).
(h * n/2) + ((h-1) * n/4) + ((h-2)*n/8) + ... + (0 * 1).
for (i = n - 1; i > 0; i--) {
arr[i] = deleteMax();
}
h*n/2 + (h-1)*n/4 + ... + 0 * 1.
T = O(log(1) + log(2) + .. + log(n)) = O(log(n!))
So total number of traversal would be:-
T(n) = sigma((2^(logn-h))*h) where h varies from 1 to logn
T(n) = n((1/2)+(2/4)+(3/8)+.....+(logn/(2^logn)))
T(n) = n*(sigma(x/(2^x))) where x varies from 1 to logn
and according to the [sources][1]
function in the bracket approaches to 2 at infinity.
Hence T(n) ~ O(n)
Green = n/2^1 * 0 (no iterations since no children)
red = n/2^2 * 1 (heapify will perform atmost one swap for each red node)
blue = n/2^3 * 2 (heapify will perform atmost two swaps for each blue node)
purple = n/2^4 * 3 (heapify will perform atmost three swaps for each purple node)
->(n/2^1 * 0) + (n/2^2 * 1)+ (n/2^3 * 2) + (n/2^4 * 3) +...+ (n/2^(h+1) * h)
-> n * ( 0 + 1/4 + 2/8 + 3/16 +...+ h/2^(h+1) )
-> ( 0 + 1/4 + 2/8 + 3/16 +...+ h/2^(h+1) )