保持Prim算法的不变性

时间:2016-03-25 04:56:46

标签: algorithm tree prims-algorithm

算法2课程中的Tim Roughgarden讲授了以下方法来更新最小堆中的相邻顶点(从堆中提取min后):

When a vertice v is added to the MST:
  For each edge (v,w) in the unexplored tree:
      1. Delete w from the min heap.
      2. Recompute the key[w] (i.e. it's value from the unexplored tree
         to the explored one).
      3. Add the value back to the heap.

所以,基本上这涉及从堆中删除(而heapify采用O(logn))然后重新插入(再次O(logn))

相反,如果我使用以下方法:

For each edge (v,w) in the unexplored tree:
    1. Get the position of the node in the heap(array) using HashMap -> O(1)
    2. Update the value in place.
    3. Bubble up or bubble down accordingly. -> O(logn)

虽然它们是渐近相同的,但后者给出了更好的常数。那么它比课程中的更好吗?或者我错过了什么?

1 个答案:

答案 0 :(得分:1)

渐近相同,你会得到一个更好的常数因子。您尝试使用HashMap实现的是使用 O(n)额外空间。此外,in worst case,它需要 O(logn)额外的时间,与从堆中删除相同的费用。然而,其与logn成正比的概率非常低。您可以查看要使用的probabilistic performance analysis特定HashMap实现。如果您有兴趣了解更多相关信息。

我可以提出一个更好的解决方案,避免使用HashMap,因此更容易观察/分析常数因素,因为不需要进行概率分析。

解决方案是将键值存储在外部数组A中并覆盖堆的比较函数,以便根据存储在A中的相应值来比较其中的元素。

换句话说,许多堆实现中的默认比较函数如下所示。

function compare(a, b):
    return a < b

更新时,您会将其更改为:

function compare(a, b):
    return A[a] < A[b]

在数组A中,每个顶点v都有一个相应的单元格,导致 O(n)额外的空间使用,就像你的HashMap想法一样。但是,在向已发现的节点添加v时更新该值,即使在最坏的情况下也会花费 O(1)时间。

可能无法根据您实现的编程语言和用于堆的库进行此更新,但可以使用多种语言和语言,包括但不限于C ++的std。 :: STL的priority_queue。如果您正在尝试使用这样的自定义数据结构,那么您也可以使用自定义堆实现来实现它。