参考:《算法导论》第23章
最小生成树:在一个连通无向图中找到一个无环子集,既能将所有结点连接起来,又具有最小的权重。
最小生成树有3个性质:
- 最小生成树是树,因此其边数等于定点数减1,且树内一定不会有环;
- 对给定的图G(V,E),其最小生成树可以不唯一,但是其边权之和一定是唯一的;
- 由于最小生成树是无向图上生成的,因此其根结点可以是这棵树上的任意一个结点。
kruskal和prim算法都是贪心算法,选择在当前看来最好的选择。
如果是稠密图(边多),选择prim算法,如果是稀疏图(边少),选择kruskal算法。
克鲁斯卡尔算法
int kruskal()
{
令最小生成树的边权之和为ans,最小生成树的当前边数是NumEdge;
将所有边按边权从小到大排序;
for(从小到大遍历所有边)
{
if(当前测试边的两个端点在不同的连通块中){
将该测试边加入到最小生成树中;
ans += 测试边的边权;
最小生成树的当前边数NumEdge加1;
当边数NumEdge等于顶点数减1时结束循环;
}
}
return ans;
}
kruskal算法的时间复杂度主要来源于对边的排序,因此其时间复杂度为O(ElogE),其中E是图中边的个数,该算法适合顶点数较多,边数较少的情况,和prim算法正好相反。
普利姆算法
//G为图,数组d为顶点与集合S的最短距离
Prim(G, d[]){
初始化;
for(循环n次){
u = 使d[u]最小的未被访问的顶点的标号;
记u已被访问;
for(从u出发能到达的所有顶点v){
if(v未被访问 && 以u为中介点使得v与集合S的最短距离d[v]更优){
将G[u][v]赋值给v与集合S的最短距离d[v];
}
}
}
}
时间复杂度为O(n^2),只与图中顶点个数有关,与边数无关,因此prim算法适用于稠密图。