问题
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?
回答1:
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)
来源:https://stackoverflow.com/questions/29594568/running-time-of-prims-algorithm