使用优先级队列的Prims算法的复杂性?

时间:2012-11-25 23:29:23

标签: java algorithm minimum-spanning-tree prims-algorithm

我使用邻接矩阵,优先级队列是数据结构。

根据我的计算,复杂性为V^3 log V

  • while循环:V
  • 检查相邻的顶点:V
  • 检查队列是否已存在该条目,并更新该条目:V log v

但是,我到处都读到复杂性为V^2

请解释一下。

2 个答案:

答案 0 :(得分:4)

如果您使用Fibonacci堆,则提取最小值为O(lg V)摊销成本并更新其中的条目O(1)已摊销。

如果我们使用这个伪代码

while priorityQueue not empty
    u = priorityQueue.exractMin()
    for each v in u.adjacencies
        if priorityQueue.contains(v) and needsWeightReduction(u, v)
            priorityQueue.updateKeyWeight(u, v)

假设实施具有priorityQueue.contains(v)needsWeightReduction(u, v)的恒定时间。

需要注意的是,您可以稍微加强检查邻接关系。虽然外循环运行V次,并且检查任何单个节点的邻接是最差V操作,但您可以使用聚合分析来实现永远不会检查超过E邻接(因为只有E边缘)。并且E <= V^2,所以这是一个稍微好一点的界限。

因此,你有外循环V次,内循环E次。提取min运行V次,并且更新堆中的条目将运行E次。

  V*lgV + E*1
= O(V lgV + E)

同样,由于E <= V^2你可以使用这个事实代替并获得

  O(V lgV + V^2)
= O(V^2)

但在考虑稀疏图时,这是一个更宽松的界限(虽然正确)。

答案 1 :(得分:0)

使用基于最小堆的优先级队列,时间复杂度为O(ElogV)。

正如您所说,外部while循环是O(V),因为它循环遍历每个顶点,因为每个顶点都需要添加到MST一次。

对于while循环中考虑的每个顶点,需要执行以下两个步骤:

  1. 选择下一个边添加到MST。根据基于最小堆的优先级队列的属性,根元素将始终是最小的元素。因此,选择下一条成本最低的边将是根元素的O(1)提取。提取后,需要以保持优先级队列的方式移动其余值。由于队列代表平衡的二叉树,因此在最坏的情况下,这种移位可能发生在O(logV)中。

  2. 优先级队列已更新。入射到新顶点的边可能需要在队列中更新其成本,因为我们现在将考虑与新添加的顶点及其相邻像素之间的边相关的成本(但是,如果它们通过具有成本低于新推出的边缘,因为我们正在寻求最低成本,因此不会更新成本)。同样,这将是O(logV),因为在最坏的情况下,需要在表示队列的平衡二叉树的整个长度上移动顶点。

步骤1发生V次,因为它在while循环中发生一次,所以总计O(VlogV),而步骤2在最坏的情况下发生E次,因为每个边都附着到当前顶点,因此它们都需要要更新,这意味着总计O(ElogV)。设置为O(E),因为它需要将优先级队列中的每个边缘成本初始化为无穷大。

使用基于最小堆的优先队列的总时间复杂度= O(E + VlogV + ElogV)= O(ElogV)

当您看到复杂度为O(V ^ 2)时,您可能正在研究不使用堆的实现。在这种情况下,外部while循环仍为O(V)。瓶颈在于选择要添加到MST的下一个顶点(即O(V))的步骤,因为您需要检查与每个相邻节点关联的成本以找到最低的成本,这在最坏的情况下意味着检查所有其他节点。因此,复杂度为O(V * V)= O(V ^ 2)。

另外,在非常密集的图中,O(ElogV)变为O(V ^ 2),因为在任何图中,最多可以有E = V ^ 2个总边。