[英]Complexity of Prims Algorithm using Priority Queue?
我正在使用邻接矩阵,优先级队列是数据结构。
根据我的计算,复杂度是V^3 log V
:
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 循环中考虑的每个顶点,需要执行以下两个步骤:
选择下一条边添加到 MST。 根据基于最小堆的优先级队列的属性,根元素总是最小的元素。 因此,选择下一个边,即成本最低的边,将是对根元素的 O(1) 提取。 提取后剩余的值需要以维持优先级队列的方式移动。 由于队列表示平衡二叉树,因此在最坏的情况下,这种偏移可能会在 O(logV) 内发生。
更新优先级队列。 与新顶点相关的边可能需要在队列中更新它们的成本,因为我们现在将考虑与新添加的顶点及其邻居之间的边相关的成本(但是,如果它们通过一条边与先前添加的顶点相邻)成本低于新引入的边缘,成本不会更新,因为我们正在寻找最低成本)。 这也是 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.