一、普里姆算法(找顶点)
1、算法思想
从图中任意取出一个顶点,把它当成一棵树,然后从与这棵树相接的边中选取一条最短(权值最小)的边,并将这条边及其所连接的顶点也并入这棵树中,此时得到了一棵有两个顶点的树。
然后从与这棵树相接的边中选取一条最短的边,并将这条边及其所连顶点并入当前树中,得到一棵有3个顶点的树。
以此类推,知道图中所有顶点都被列入树中为止,此时得到的生成树就是最小生成树。
2、普里姆算法执行过程
从树中某个顶点v0开始,构造生成树的算法执行过程如下:
①将v0到其他顶点的边当作后选边;
②重复以下步骤n-1此,使其他n-1个顶点被并入到生成树中。
1)从后选边中挑选出权值最小的边输出,并将与该边到另一端相接的顶点v并入树中;
2)考察所有剩余顶点vi,如果(v,vi)的权值比lowcost[vi]小,则用(v,vi)的权值更新lowcost[vi];
3、普里姆算法代码
/*
在用普里姆算法构建最小生成树的过程中,需要建立两个数组vset[]和lowcost[]。
vset[i]=1表示顶点i已经被并入生成树中,vset[i] =0表示顶点i还未被并入生成树中;
lowcost[]数组中存放当前生成树到剩余各顶点最短边的权值。
*/
typedef struct{
int no; //顶点编号
char info; //顶点其他信息
}VertexType; //顶点类型
typedef struct{
int edges[maxSize][maxSize];
int n,e;
VertexType vex[maxSize];
}MGraph;
void Prim(MGraph g, int v0,int &sum){
int lowcost[maxSize],vset[maxSize],v; //lowcost中存放的是剩余的各个顶点,距离最小生成树最小的权值。例如lowcost[2]=1.2,顶点2不在最小生成树中,那么说明顶点2距离最小生成树的最短权值为1.2
int i,j,k,min; //i、j作遍历用,k存放距离最小生成树最近的顶点,min存放未入树顶点离最小生成树的最小距离
v=v0;
for(i=0;i<g.n;++i){ //遍历所有顶点,初始化lowcost和vset
lowcost[i]=g.edgs[v0][i];
vset[i]=0; //入树的顶点标记为1,未入树标记为0
}
vset[v0]=1; //将v0并入树中,标记为已并入
sum=0; //sum清零用来累计树的权值
for(i=0;i<g.n-1;++i){ //遍历未并入树的剩下的n-1个顶点
min=INF; //INF是一个已经定义的比图中所有边权值都大的常量,相当于对min进行一个初始化操作
for(j=0;j<g.n;++j){
if(vset[j]==0&&lowcost[j]<min){ //顶点j未入树,且j距离最小生成树的最小距离比 min小
min=lowcost[j];
k=j; //那么就将j顶点作为准备要入树的顶点(因为j顶点距离最小生成树最近)
}
}
vset[k]=1; //将顶点k入树
v=k; //将v指向最新入树的顶点,接下来更新最小生成树的权值,以及lowcost(未入树顶点离最小生成树最小距离)
sum+=min;
for(j=0;j<g.n;++j){
if(vset[j]==0&&g.edges[v][j]<lowcost[j])
lowcost[j]=g.edges[v][j];
}
}
}
二、克鲁斯卡尔算法(找边)
1、算法思想
将图中按照权值从大到小排序,然后从最小边开始扫描各边,并检测当前边是否为候选边,即是否该边的并入会构成回路,如不构成回路,则将该边并入当前生成树中,直到所有边都被检测完为止。
2、克鲁斯卡尔算法代码
typedef struct{
int no;
char data;
}VexType;
typedef struct{
int edgs[maxSize][maxSize];
int n,e;
VexType vex[maxSize];
}MGraph;
typedef struct{
int a,b; //a,b为一条边所连的两个顶点
int w; //边的权值
}Road;
Road road[maxSize];
int v[maxSize]; //定义并查集数组
int getRoot(int a){ //在查并集中查找根节点的函数
while(a!=v[a])
a=v[a];
return a;
}
void Kruskal(MGraph g,int &sum,Road road[]){
int i;
int N,E,a,b;
N=g.n;
E=g.e;
sum=0;
for(i=0;i<E;++i)
v[i]=i;
sort(road,E); //对road数组中的E条边按其权值从小到大排序
for(i=0;i<E;++i){
a=getRoot(road[i].a);
b=getRoot(road[i].b);
if(a!=b){
v[a]=b;
sum+=road[i].w;
}
}
}