繁体   English   中英

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

[英]Complexity of Prims Algorithm using Priority Queue?

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

根据我的计算,复杂度是V^3 log V

  • While 循环: V
  • 检查相邻顶点: V
  • 如果条目已经存在,则检查队列并更新: V log v

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

请解释。

如果您使用斐波那契堆,则提取最小值是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 次。 提取最小值运行V次,更新堆中的条目运行E次。

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

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

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

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

使用基于最小堆的优先级队列,时间复杂度为 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 个总边。

如果不使用优先级队列,则使用二叉堆它包括两个基本步骤: 1.Insertion 使用插入排序算法的插入时间复杂度在最坏情况下为 O(E^2) 2.Deletion 删除每个出队需要 O(1) 并且dequeue 相当于顶点数,如果使用映射,否则将几乎相同所以,这里的总时间复杂度是 O(V+E^2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM