0

Suppose that all edge weights in a graph are integers in the range from 1 to |V|. How fast can you make Prim's algorithm run? What if the edge weights are integers in the range from 1 to W for some constant 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)

According to my textbook:

The running time of Prim's algorithm depends on how we implement the min-priority queue Q. If we implement Q as a binary min-heap, we can use the BUILD-MIN-HEAP procedure to perform lines 1-5 in O(V) time. The body of the while-loop executes |V| times, and since each EXTRACT-MIN operation takes O(lg V) time, the total time for all calls to EXTRACT-MIN is O(VlgV). The for-loop in lines 8-11 executes O(E) times altogether, since the sum of the lengths of all adjacency lists is 2|E|. Within the for-loop, we can implement the test for membership in Q in line 9 in constant time by keeping a bit for each vertex that tells whether or not it is in Q, and updating the bit when the vertex is removed from Q. The assignment in line 11 involves an implicit DECREASE-KEY operation on the min-heap, which a binary min-heap supports in O(lg V) time. Thus, the total time for Prim's algorithm is O(V lg V+E lg V)=O(E lg V).

The lines 1-4 require O(V) time. I have read some explanations why the BUILD-MIN-HEAP procedure requires linear time, but I haven't understood them. Could you explain to me why the time complexity of the MIN-HEAP procedure is O(V)?

Furthermore, I thought that at a min-heap, the minimum element is at the root. So, why does each EXTRACT-MIN operation take O(lg V) time?

Then, the for-loop is executed O(Σ_{v in V.G} deg(v)) times, right? Could you explain me why Σ_{v in V.G} deg(v)=2E?

Also, what would be different if we would know that the edge weights are integers in the range from 1 to W for some constant W?

EDIT:

Suppose that all edge weights in a graph are integers in the range from 1 to |V|. How fast can you make Prim's algorithm run?

What could we change at the above algorithm, so that the Prim's algorithm runs as fast as possible?

Mary Star
  • 359
  • 5
  • 23

1 Answers1

2

Answer-1

The first question can be found in stackoverflow from- this question.

Answer-2

Extract min operation gets the minimum element from root in O(1) time but along with that we need to perform operations that will make the next Extract min operation to give min element in O(1) time. What do we do? We just swap the root element with the rightmost leaf node and then delete that leaf node and heapify the root which may percolate down the new root to leaf node and that mean O(logn) complexity. (as 2^h=n then h=log2(n)).

Answer-3

For undirected graph

Now why 2E. okay! each node has some edge connected to it.(if not connected then it's degree is zero). Now node has degree n means it has n edges connected to it. Now let's take an example

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);

Why so? You can consider model this situation as an handshake b/2 friends. Each node denotes friends and each edge denotes handshake. If you shook hand with B then B will handshake with you also. So each handshake(edge) is considered twice by the nodes(friends).

Note: For directed graph the result will be equal to E

Answer-4

These links already explain it. Check this hope everything will be clear

1.link1

2.link2

let's be clear over here. What is the algorithm-In cormen it is given this way-

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.

So total comlexity= O(V)+O(VlogV)+O(ElogV) = O((V+E)logV) //VlogV dominates V

Now if all the edge weights are in range 1 to |V| then we can just take an array of lists A[1..|V|]. Now let's say edge weights are 1(E1),3(E2),2(E3),5(E4),7(E5), 3(E6)and there 7 vertices and 6 edges.

Array of lists initially

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

Now you apply the method of counting sort- for each edge weight you put that edge in corresponding array location like

Now after encounterng the edge E1 the array will be

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

then after that for edge E2

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

So after traversing all edges you get

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

Probably now you can understand why did some answer mentioned of |V| lists or |W| lists from this diagram.

Now what you can get all the minimums from the array in O(V) time. Normally for wide range of weights heap data structure is used to store the edges.

However, in this case, the weights are either 1 .. |V| and so you can simply store the edges in |V| separate lists, one for edges with weight 1 to |V|.

To find the edge with lowest weight you simply take one from the first list, unless it is empty, in which case you take an edge from the second list.

Accessing and deleting an element from a list is O(1) and you just delete the topmost element from the list. so Prim's algorithm will run in O(V*W+E).

So if W=O(V) then it runs in O(V^2+E)

If the weights are in range 1..W (W=O(1) constant) then complexity similarly will be O(V*W+E). ~O(V+E).

The pseudocode

In C

struct edge { int u,v,w; } struct listnode { edge 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
    }

}

Complexity Analysis

Algo:

Let's the weights are in the range 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)
    }

}

So complexity=O(|W|)+O(|W|.|V|)+O(|E|)~O(E+VW) When W=O(V) then T(V,E)= O(E+VV)=O(E+V^2)

Community
  • 1
  • 1
user2736738
  • 28,590
  • 4
  • 37
  • 52
  • I think that I have understood your answers 1,2,3... But.. I haven't understood how fast we can make Prim's algorithm run, assuming that all edge weights in a graph are integers in the range from 1 to |V|. What can we do? Do we have to create a list, a queue or an array? If so, what can we do? I haven't understood it... – Mary Star Apr 14 '15 at 20:21
  • @evinda.: You need not maintain a priority queue and that's the basic idea. But we can't do it for wide range weights as that will require many more lists..high space requirement. That's why we use heap in wide range weights. – user2736738 Apr 15 '15 at 11:40
  • I have't understood what the array of lists will contain. Do we create an array of length |V| , A[1....|V|] and put at each position the number of edges that are equal to the number of the position? Or have I understood it wrong? – Mary Star Apr 15 '15 at 12:30
  • @evinda.: You have to put the edges over there..that means the dtata structure that you will select for edge..like for example it maybe a pair like this `(u,(v,w))` that is an ordered pair where u,v are vertices and w is the weight.The edge is assumed to be from u to v.Those are being kept in each list of that array of list. Now whenever you are removing an edge you just get the topmost or last edge from a given slot. Similarly is the case for insertion.List part is pretty standard. Insertion and deletion.You may want to store the no elements present in a slot of array,that's implementation. – user2736738 Apr 15 '15 at 12:50
  • So you mean that at each position of the array A[1...|V|] we have a list which contains three numbers u,v,w and we sort the array as for the last element w? Or have I understood it wrong? – Mary Star Apr 15 '15 at 13:18
  • @evinda.: Yes actually as we insert the edeges in the array we know that they are put in sorted order. So yeah! you have understood it clearly. This idea is basically counting sort. – user2736738 Apr 15 '15 at 13:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75292/discussion-between-amalsom-and-evinda). – user2736738 Apr 15 '15 at 13:37