Prim算法的运行时间

时间:2015-04-12 20:58:04

标签: algorithm time heap prims-algorithm

假设图中的所有边权重都是从1到| V |的整数。你能以多快的速度运行Prim的算法?如果边缘权重是1到W范围内的整数,对于某个常数W?

,该怎么办?
MST-PRIM(G,w,r)
1.  for each u∈  G.V
2.       u.key=inf
3.       u.π=NIL
4.  r.key=0
5.  Q=G.V
6.  while Q != Ø 
7.     u=EXTRACT-MIN(Q)
8.     for each v ∈  G.Adj[u]
9.         if v∈  Q and w(u,v)<v.key
10.          v. π=u
11.          v.key=w(u,v)

根据我的教科书:

Prim算法的运行时间取决于我们如何实现最小优先级队列Q.如果我们将Q实现为二进制最小堆,我们可以使用BUILD-MIN-HEAP过程在O中执行第1-5行(五)时间。 while循环的主体执行| V |由于每次EXTRACT-MIN操作需要O(lg V)时间,因此所有EXTRACT-MIN调用的总时间为O(VlgV)。第8-11行中的for循环一共执行O(E)次,因为所有邻接列表的长度之和为2 | E |。在for循环中,我们可以通过为每个顶点保留一个位来判断它是否在Q中,并且在从Q中移除顶点时更新位,从而在常量时间内对第9行中Q的成员资格进行测试。第11行中的赋值涉及最小堆上的隐式DECREASE-KEY操作,二进制最小堆支持O(lg V)时间。因此,Prim算法的总时间为O(V lg V + E lg V)= O(E lg V)。

第1-4行需要O(V)时间。我已经阅读了一些解释为什么BUILD-MIN-HEAP程序需要线性时间,但我还没有理解它们。你能解释一下为什么MIN-HEAP程序的时间复杂度是O(V)吗?

此外,我认为在最小堆中,最小元素位于根。那么,为什么每个EXTRACT-MIN操作需要O(lg V)时间?

然后,for循环执行O(Σ_{v in V.G} deg(v))次,对吗?你能解释一下为什么Σ_{v in V.G} deg(v)= 2E?

另外,如果我们知道边缘权重是一个常数W的1到W范围内的整数会有什么不同呢?

修改

  

假设图中的所有边权重都是范围内的整数   从1到| V |。你能以多快的速度运行Prim的算法?

我们可以在上述算法中改变什么,以便Prim的算法尽可能快地运行?

1 个答案:

答案 0 :(得分:2)

答案-1

第一个问题可以在stackoverflow中找到 - this question

答案-2

Extract min操作在O(1)时间内从root获取最小元素,但同时我们需要执行操作,使下一个Extract min操作在O(1)时间内给出min元素。我们做什么?我们只是将根元素与最右边的叶节点交换,然后删除该叶节点并将根堆积,这可能会将新根渗透到叶节点,这意味着O(logn)复杂度。 (因为2 ^ h = n然后h = log2(n))。

答案-3

对于无向图

现在为什么2E。好的!每个节点都有一些边连接到它(如果没有连接则它的度数为零)。现在节点有度数n意味着它有n个边连接到它。现在让我们举个例子

1---2
|  /
| /
3
1 has degree=2
2 has degree=2
3 has degree=2
-+-+-+-+-+-+-+-
so sum(deg(v))=2+2+2=6= 2*(no of edges);

为什么这样?您可以考虑将此情况建模为握手b / 2朋友。每个节点表示朋友,每个边缘表示握手。如果你和B握手,那么B也会和你握手。因此,每个握手(边缘)被节点(朋友)认为是两次。

注意:对于有向图,结果将等于E

答案-4

这些链接已经解释了它。检查这个希望一切都会很清楚

1。link1

2。link2

  

让我们在这里说清楚。什么是算法 - 在这种方式下给出了它 -

MST-PRIM(G, w, r)
 1  for each u ∈ V [G]  ~~~~~~~~~> O(V)
 2       do key[u] ← ∞
 3          π[u] ← NIL
 4  key[r] ← 0
 5   Q ← V [G]          ~~~~~~~~~> If binary min-heap used then heapification's comlexity is O(V)
 6   while Q ≠ Ø        ~~~~~~~~~> Executed |V| times
 7       do u ← EXTRACT-MIN(Q)~~~> O(logV) in binary heap
 8          for each v ∈ Adj[u] ~~~> For each vertex the degree of that vertex times it will loop. So total O(E) times
 9              do if v ∈ Q and w(u, v) < key[v]
10                    then π[v] ← u
11                         key[v] ← w(u, v)~~~> decrease key operation in min-heap(binary) O(logV) times.

因此总复杂度= O(V)+ O(VlogV)+ O(ElogV)                   = O((V + E)logV)// VlogV支配V

现在,如果所有边权重都在1到| V |的范围内然后我们可以得到一个列表A [1 .. | V |]的数组。现在让我们说边缘权重是1(E1),3(E2),2(E3),5(E4),7(E5),3(E6)以及7个顶点和6个边缘。

最初的列表数组

A  [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
    0   1   2   3   4   5   6   7

现在,对每个边缘权重应用计数排序的方法,将边缘放在相应的数组位置,如

现在在遇到边缘E1之后,阵列将是

A  [ ] [E1] [ ] [ ] [ ] [ ]  [ ] [ ]
    0    1    2  3   4    5   6   7

然后是边缘E2

A  [ ] [E1] [ ] [E2] [ ] [ ] [ ] [ ]
    0   1    2   3    4   5   6   7

所以在遍历所有边缘后,你得到

                  E6
                  | 
A  [ ] [E1] [E3] [E2] [ ] [E4] [ ] [E5]
    0    1    2    3   4    5   6   7

  

可能现在你可以理解为什么有些答案提到了| V |列表或| W |从该图表中列出。

     

现在你可以在O(V)时间内从阵列中获得所有最小值。   通常,对于宽范围的权重,堆数据结构用于存储边。

然而,在这种情况下,权重是1 .. | V |所以你可以简单地将边缘存储在| V |中单独的列表,一个用于权重为1到| V |。

的边

要查找权重最低的边,您只需从第一个列表中选择一个,除非它是空的,在这种情况下,您从第二个列表中取一个边。

从列表中访问和删除元素是O(1),您只需从列表中删除最顶层的元素。所以Prim的算法将在O(V * W + E)中运行。

因此,如果W = O(V),那么它在O(V ^ 2 + E)

中运行

如果权重在1..W(W = O(1)常数)的范围内,则复杂性类似地为O(V * W + E)。 〜O(V + E)。

伪代码

在C

结构边缘 {     int u,v,w; } struct listnode {     边e;     struct listnode * next; }

struct listnode ** A;
A=malloc(sizeof(struct list *)*N);
Intilally all of A[i]=NULL;

A[i]=malloc(sizeof(struct listnode),1);
(*A[i]).e.u=..
(*A[i]).e.v=..
(*A[i]).e.w=..

 create the array of lists don't insert anythiing.
 Then just select a vertex say s
 keep an array visisted[1..|V|]
 visited[s]=true;
 no_of_visited=1;
 recently_visted=s;
 while(all nodes are not visited)   //no_of_visited!=|V|
 {
    insert all edges from s-x (adjacent) in the array of lists.(s is recently visited) provided x is not visited
    get the minimum weight one
    if it is u-w and w is not visited
    {
        visited[w]=true;
        no_of_visited++;
        recently_visited=w;
        insert(u,w) in spanning tree
    }

}

复杂性分析

Algo:

让重量在1 .. | W |

的范围内
Then just select a vertex say s ~~~~~~~~~~> O(1)
 //keep an array visisted[1..|W|]
 for i=1 to |W| 
     visited[i]=false;   ~~~~~~~~~~> O(|W|) 
 visited[s]=true; ~~~~~~~~~~> O(1)
 no_of_visited=1; ~~~~~~~~~~> O(1)
 recently_visted=s; ~~~~~~~~~~~ O(1)
 while(all nodes are not visited) ~~~~~O(V)  //no_of_visited!=|W|
 {
    insert all edges from s-x (adjacent) in the array of lists.(s is recently visited) provided x is not visited ~~~~~O(|E|) altogether
    get the minimum weight one          ~~~~~O(|W|) 
    if it is u-w and w is not visited   --O(1)
    {
        visited[w]=true;               
        no_of_visited++;
        recently_visited=w;
        insert(u,w) in spanning tree    --O(1)
    }

}
  

因此复杂性= O(| W |)+ O(| W |。| V |)+ O(| E |)~O(E + V W)   当W = O(V)时,T(V,E)= O(E + V V)= O(E + V ^ 2)