一.最小生成树(MST):
连通图的一次遍历所经过的边的集合及图中所有顶点的集合就构成了该图的一棵生成树,对连通图的不同遍历,就可以得到不同的生成树。
如果无向连通图就是一个网,那么,它的所有生成树中必有一棵边的权值总和最小的生成树,我们称这棵生成树为最小生成树。
二.最小生成树的两种算法:
1.Prim算法:
适用范围:该算法针对顶点展开,适用于边数较多的情况。
算法描述:
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
代码实现:
/* 最小连通网Prim算法 */
Status Prim(MGraph graph, Vertex n)
{
int i, j, min = INF, index;
bool marked[MaxVertexSize];
int P[MaxVertexSize];
int cost[MaxVertexSize];
if(n < 0 || n >= graph->Nv)
return ERROR;
for(i = 0; i < graph->Nv; i++) {
marked[i] = false;
cost[i] = graph->matrix[n][i];
P[i] = n;
}
marked[n] = true;
for(i = 0; i < graph->Nv - 1; i++) {
min = INF;
for(j = 0; j < graph->Nv; j++) {
if(!marked[j] && cost[j] < min) {
min = cost[j];
index = j;
}
}
printf("%d, %d, %d\n", P[index], index, min);
marked[index] = true;
printf("%d\n", graph->Nv);
for(j = 0; j < graph->Nv; j++) {
if(!marked[j] && graph->matrix[index][j] < cost[j]) {
cost[j] = graph->matrix[index][j];
P[j] = index;
}
}
}
return OK;
}
2.Krukal算法:
适用范围:该算法针对边展开,适用于边数较少的情况。
算法描述:
1).记Graph中有v个顶点,e个边
2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
如果这条边连接的两个节点于图Graphnew中不在同一个连通分量中,添加这条边到图Graphnew中。
代码实现:
typedef struct KrusEdge {
Vertex a,b;
WeightType weight;
} KrusEdge;
/* 冒泡排序 */
Status sort(KrusEdge s[], int n)
{
bool flag;
int i, j;
KrusEdge temp;
if(!s)
return ERROR;
for(i = 0; i < n - 1; i++) {
for(j = i + 1; j < n; j++) {
if(s[j].weight < s[i].weight) {
temp = s[j];
s[j] = s[i];
s[i] = temp;
}
}
}
return OK;
}
/* 最小连通网Kruskal算法 */
Status Kruskal(MGraph graph)
{
int i, j, k = 0, s1, s2;
int vsrc[MaxVertexSize];
KrusEdge edge[MaxEdgeNum];
if(!graph)
return ERROR;
for(i = 0; i < graph->Nv; i++)
for(j = 0; j < graph->Nv; j++) {
if(graph->matrix[i][j] != 0 && graph->matrix[i][j] != INF) {
edge[k++] = {i, j, graph->matrix[i][j]};
}
}
for(i = 0; i < graph->Nv; i++)
vsrc[i] = i;
sort(edge, k);
k = 0;
i = 1;
while(i < graph->Nv) {
s1 = vsrc[edge[k].a];
s2 = vsrc[edge[k].b];
if(s1 != s2) {
printf("%d, %d, %d\n", edge[k].a, edge[k].b, edge[k].weight);
for(j = 0; j < graph->Nv; j++) {
if(vsrc[j] == s2)
vsrc[j] = s1;
}
i++;
}
k++;
}
}