图的基本概念里有提到,一个连通图的生成树是一个极小的连通子图,它含有图中的全部顶点,但只有构成一棵树的n-1条边。
最小生成树:构造连通图的最小代价生成树
即在上图(网结构)中找到权值之和最小的生成树的路径。
实现最小生成树有两种算法:
普里姆(Prim)算法
构造邻接矩阵实现
void MiniTree(MGraph G)
{
int min,i,j,k;
int adjvex[MAX]; //保存相关顶点的下标
int lowcost[MAX]; //保存相关顶点间边的权值
lowcost[0]=0 //初始化第一个权值为0,表示V0加入生成树
//当lowcost的值是0时,表示该顶点已经加入生成树
for(i=1;i<G.numVertexes;i++) //循环除下标为0外的全部顶点
{
lowcost[i]=G.arc[0][i]; //将与V0顶点存在边的边上权值存入数组
adjvex[i]=0; //初始化都为V0的下标
}
for(i=1;i<G.numVertexes;i++)
{
min=INFINITY; //初始化最小权值为无穷
j=1;k=0;
while(j<G.numVertexes) //循环全部顶点
{
if(lowcost[j]!=0&&lowcost[j]<min)
{//权值不为零表示未加入生成树,且权值小于min(min是无穷值)
min=lowcost[j]; //让当前权值成为最小值
k=j; //将当前最小权值的顶点下标存入k
}
j++;
}
printf("(%d,%d)",adjvex[k],k); //打印当前顶点边中权值最小的边
lowcost[k]=0; //表示此顶点已经加入树
for(j=1;j<G.numVertexes;j++) //循环所有顶点
{
if(lowcost[j]!=0&&G.arc[k][j]<lowcost[j])
{//若下标为k的顶点各边的权值小于此前未加入树的权值
lowcost[j]=G.arc[k][j]; //将较小权值存入lowcost
adjvex[j]=k;
}
}
}
}
adjvex[0]=0的意思是我们从顶点V0开始
9-13行,表示我们读取邻接矩阵右图中的第一行数据。数值赋值给lowcost数组,
此时其值是{0,10,65535,65535,65535,11,65535,65535,65535},adjvex全部为0。
初始化完成。
14-40行,构造最小生成树
46行将min设置为极大值65535,目的是为了找到一定范围内的最小权。
19-28行,不断修改min为当前lowcost数组中的最小值,k存储最小权值的顶点下标
经过循环后 min=10,k=1
29行将(0,1)打印出来,表示V0到V1边是最小生成树的第一条边
30行将V1纳入最小生成树中,此时low数组{0,0,65535,65535,65535,11,65535,65535,65535}
32-39行,K=1,故查找第V1行的各个权值与low数组的比较,更小则加入数组,并将K存入adjvex,也就是找V1各边看有没有权值小于V0到顶点的边的权值的
V1行有18 16 12 比65535小,故low{0,10,18,65535,65535,11,16,65535,12}adjvex数组{0,0,1,0,0,0,1,0,1} 初始时都为0
lowcost[j]!=0说明V0和V1已经纳入树内无需比较
再次循环14-44行,此时min=11,K=5,adjvex[5]=0.
故第二条边是(V0,V5)
lowcost{0,0,18,65535,26,0,16,65535,12}
adjvex{0,0,1,0,5,0,1,0,1};
此后一样循环
注:
if (lowcost[j]!=0 && G->arc[k][j]<lowcost[j])
如果顶点j没有加入生成树 并且k顶点到j顶点的权值要小于对应的lowcost数组中第j个元素的权值,
那么就讲该权值存入Lowcost数组并将j存入adjvex中。也就是说,当我加入了一个k顶点到生成树中以后,
那么生成树中必然会多一些k顶点与其邻接点的边出来,那么我要看下这些边上的权值是否有小于lowcost数组中对应位置上的 值(初始状态lowcost数组中的值都是v0到各个顶点的边的权值),如果小于那么就说明顶点k到顶点j的边的权值要比V0到j的 边的权值小。我们当然要保存这个结果,那么就修改adjvex[j] = k lowcost[j] = G->arc[k][j]; 即k顶点到j顶点的权值为 G- >arc[k][j];
以后每次加入一个新的顶点都要看其与其邻接点的边上的权值是否要小于lowcost数组中对应顶点的权值。如果小于就修改
然后找到Lowcost数组中最小的权值 并将其与顶点输出