假设图中的所有边权重都是从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的算法尽可能快地运行?
答案 0 :(得分:2)
第一个问题可以在stackoverflow中找到 - this question。
Extract min操作在O(1)时间内从root获取最小元素,但同时我们需要执行操作,使下一个Extract min操作在O(1)时间内给出min元素。我们做什么?我们只是将根元素与最右边的叶节点交换,然后删除该叶节点并将根堆积,这可能会将新根渗透到叶节点,这意味着O(logn)复杂度。 (因为2 ^ h = n然后h = log2(n))。
对于无向图
现在为什么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
这些链接已经解释了它。检查这个希望一切都会很清楚
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)