您的位置:首页 > 其它

最小生成树算法(Prim和Kruskal)

2015-03-10 16:44 274 查看
无向连通图的最小生成树

设G=(V,E)是一个无向连通图,生成树上各边的权值之和称为该生成树的代价,在G的所有生成树中,代价最小的生成树即为其最小生成树。

Prim(普里姆)算法的基本思想是:

设 G=(V,E) 是一个无向连通图,令T=(U,TE) 是 G 的最小生成树。T的初始状态为 U={v0}(v0∈V),TE={},然后重复执行下述操作:

在所有 u∈U,v∈V-U 的边中找一条代价最小的边(u,v) 并入 U,直至 U=V 为止。此时TE中必有 n-1 条边,T 就是最小生成树。

代码如下:

[cpp] view
plaincopy

void MiniSpanTree(MGraph G)

{

int min,i,j,k;

int adjvex[MAXVEX];//保存相关顶点下标

int lowcost[MAXVEX];//保存相关顶点间边的权值

adjvex[0] = 0;//初始化第一个顶点下标为0

lowcost[0] = 0;//初始化第一个权值为0,即Vo加入生成树

//lowcost的值为0,表示此下标的顶点已经加入生成树

for (i = 1; i < G.vertexNum; i++)//循环除0外的全部顶点

{

lowcost[i] = G.arc[0][i];//将Vo顶点与之有边的权值存入数组

adjvex[i] = 0;//初始化都为Vo的下标

}

for (i = 1; i < G.vertexNum; i++)

{

min = INFINITE;//初始最小值为极大∞

j = 1;

k = 0;

while (j < G.vertexNum)//循环全部顶点

{

if (lowcost[j] != 0 && lowcost[j] < min)//如果权值不为0且小雨min

{

min = lowcost[j];//让当前权值成为最小值

k = j;//将当前最小值的下标存入k

}

j++;

}

printf("(%d,%d)",adjvex[k],k);//输出当前顶点边中权值最小边

lowcost[k] = 0;//0表示该顶点已完成

for (j = 1; j < G.vertexNum; j++)//循环所有顶点

{

//若下标为k的顶点的各边权值小于此前这些顶点未被加入生成树的权值

if (lowcost[j] != 0 && G.arc[k][j] < lowcost[j])

{

lowcost[j] = G.arc[k][j];//将较小权值存入lowcost

adjvex[j] = k;//将下标为k的顶点存入adjvex

}

}

}

}

Kruskal(克鲁斯卡尔)算法的基本思想是:

基本思想:设无向连通网为 G=(V, E),令 G 的最小生成树为 T=(U, TE),其初态为 U=V,TE={ },然后,按照边的权值由小到大的顺序,考察 G 的边集E中的各条边。若被考察的边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T中的连通分量个数为1时,此连通分量便为 G 的一棵最小生成树。

代码如下:

[cpp] view
plaincopy

/对边集数组Edge结构的定义

typedef struct

{

int begin;

int end;

int weight;

}Edge;

void MiniSpanTree(MGraph G)

{

int i,n,m;

Edge edges[MAXEDGE];//定义边集数组

int parent[MAXVEX];//定义一数组用来判断边与边是否形成环路

//此处省略将邻接矩阵G转化为边集数组edges并按权值由小到大排序的代码

for (i = 0; i < G.vertexNum; i++)

parent[i] = 0;//初始化为0

for (i = 0; i < G.edgeNum; i++)//循环每一条边

{

n = Find(parent,edges[i].begin);

m = Find(parent,edges[i].end);

if (n != m)//假如n与m不相等,说明此边没有与现有的生成树形成环路

{

parent
= m;//将此边的结尾顶点放入下标为起点的parent中,表示此顶点已经在生成树中

printf("(%d,%d) %d ",edges[i].begin,edges[i].end,edges[i].weight);

}

}

}

int Find(int * parent,int x)//查找连线顶点的尾部下标

{

while (parent[x] > 0)

x = parent[x];

return x;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: