【问题标题】:What is the time complexity of heapifyUp() method?heapifyUp() 方法的时间复杂度是多少?
【发布时间】:2018-01-18 20:47:56
【问题描述】:

我见过一些使用 heapifyUp() 和 heapifyDown() 方法。我们不能使用 heapifyDown() 来实现 heapifyUp() 吗:

 for( int i = heap_size/2; i >= 0; i--)
   heapifyDown(i);

我相信上述代码 sn-p 的时间复杂度是 O(n)(根据 Cormen)。

现在 heapifyUp() 实现如下:

 while(i!=0 && arr[parent(i)]>arr[i])
 {
      swap(arr[i],arr[parent(i)]);
      i = parent(i);
 }

如果我没记错的话,上述实现的时间复杂度是 O(logn)

现在由于 O(logn) 比 O(n) 更好,所以 heapifyUp() 方法当然做得更好。那么Cormen为什么要使用bottom-up heapify(方法一)来建堆呢??

如果我错了,请纠正我,哪个实现更好?

【问题讨论】:

  • 你能给你引用的 Cormen 论文的链接吗?是专门讨论在构建堆时添加值后会发生什么?

标签: data-structures heap priority-queue heapsort binary-heap


【解决方案1】:

首先,您的两个代码 sn-ps 正在做两件完全不同的事情。执行heapifyDown() 的代码将整个数组重新排列到堆中。它移动了数组中一半的元素,整个过程的时间复杂度只有O(n)。

您发布的heapifyUp() 代码将单个元素向上移动到堆中。它的时间复杂度是 O(log n)。如果您要使用该方法从数组构建堆,则总时间复杂度将为 O(n log n)。

heapifyUp()heapifyDown() 用于两种不同的用途,每种用途都有其原因。

heapifyUp() 在将项目插入堆时调用。插入项时,将其放置在堆的末尾,然后通过堆过滤。最坏的情况是 O(log n)。平均情况有很大不同。平均而言,该项目有一半的时间不必移动,因为它属于底行。四分之一的时间它只需要向上移动一个级别。八分之一的时间只需要移动两个级别,等等。

heapifyDown() 用于删除最小元素。我们将最后一项从堆中移动到根,然后将它向下移动到堆中适当的位置。从顶部向下移动时,heapifyDown() 的最坏情况为 O(log n)。平均情况也是 O(log n)。

您发布的循环是 heapifyDown() 的第二个特殊用法:

for( int i = heap_size/2; i >= 0; i--)
  heapifyDown(i);

这是 O(n),因为它利用了堆结构。

首先,请注意它只移动了一半的项目。其次,并非每个项目都从顶部一直移动。例如,如果我们有 127 个项目的堆(这将是一个有 7 个级别的完整堆),那么其中 64 个项目甚至都不会被检查,因为它们已经在底层。 32 个项目只移动一个位置。 16 个项目最多移动 2 个级别,以此类推。你最终得到:

64*0 + 32*1 + 16*2 + 8*3 + 4*4 + 2*5 + 1*6
0 + 32 + 32 + 24 + 16 + 10 + 6 = 120 swaps

使用循环创建堆时最多 120 次交换。

可以在向堆中插入新项目时使用 heapifyDown(),但这会比使用 heapifyUp() 慢,因为平均而言,插入的每个项目都必须移动得更远。从底部插入。

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 2010-12-23
    • 2011-02-16
    • 2019-05-14
    相关资源
    最近更新 更多