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)
虽然它们是渐近相同的,但后者给出了更好的常数。那么它比课程中的更好吗?或者我错过了什么?
答案 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。如果您正在尝试使用这样的自定义数据结构,那么您也可以使用自定义堆实现来实现它。