最小生成树:n个顶点,用n条边构造连通网最小权值和的生成树。
1.普里姆(prim)算法:
算法流程:
第一步:创建两个一维数组lowcost和adjvex,长度都为顶点个数,此图中长度为9。
第二步:adjvex[0]=0,表示从顶点V0开始,
lowcost[0]=0,表示V0被纳入最小生成树了,之后凡是lowcost数组中被设为0的下标对应的顶点都表示被纳入最小生成树中。
第三步:把上图的邻接矩阵的第一行的数据赋给数组lowcost,∞用65535表示,则此时lowcost值为:[0,10,65535,65535,65535,11,
65535,65535,65535],adjvex则全部为0。
第四步:定义变量min存储lowcost数组的最小值,已经是生成树的顶点不参与最小值的查找,并定义变量k存储该最小值的下标。则min=10,k=1。
第五步:打印(adjvex[k],k),也就是(0,1),表示V0到V1为最小生成树的第一条边。
第六步:将lowcost[k]=0,表示把顶点V1纳入最小生成树中。此时lowcost数组的值为:[0,0,65535,65535,65535,11,65535,65535,
65535]。
第七步:查找邻接矩阵第k行的各个权值与lowcost数组的对应值比较,从1开始,若更小则更改lowcost的对应值,并将k值存入adjvex数组中。因为k=1,所以第1行为:[0,18,65535,65535,65535,16,65535,12]
已纳入最小生成树的顶点的值不参与比较
所以更改后的lowcost值为:[0,0,18,65535,65535,11,16,65535,12]
更改后的adjvex值为:
[0,0,1,0,0,0,1,0,1]
第八步:此时min=11,k=5,打印(0,5),生成最小生成树的第二条边,V0到V5。
第九步:重复上述操作,直到最小生成树的8条边都找出来。
最小生成树的边有:(V0,V1),(V0,V5),(V1,V8),(V8,V2),(V1,V6),(V6,V7),(V7,V4),(V7,V3)
理解普利姆算法:
设两个顶点的集合,一个为空U,一个包含图的所有顶点V。然后从V集合取出一个顶点放到空集合U里,然后找出该顶点的最小权值边,并把该边的另一个顶点从V集合中取出放到U集合,继续找出U集合中通往该集合之外的顶点的最小权值边,并把该边的另一个顶点从V集合中取出放到U集合,循环这个过程,直到U集合包含图的全部顶点。
克鲁斯卡尔算法:
需要用到图的边集数组,并对它们的权值按从小到大排序:
算法流程:
第一步:声明一个数组parent,并把它所用元素初始化为0,edges数组已存在边集数组中。
第二步:循环每一条边,调用Fine函数为变量n,m赋值。Fine函数要求传入parent数组和一个int值f,循环直到parent[f]不大于0为止,否则执行f=parent[f],最后返回f。(返回的是该顶点在最小生成树中与它连通的"最大顶点"(终点))
第三步:n=Fine函数传入parent数组和边的begin值,第一条边传入parent数组和4,因为parent[4]=0,所以n=4。
第四步:m=Fine函数传入parent数组和边的end值,第一条边传入parent数组和7,因为parent[7]=0,所以m=7。
第五步:如果n!=m,此边没有与现有生成树形成环,执行parent[n]=m,并打印该边和权值。因此parent[4]=7,打印(4,7)7。此时parent数组为:[0,0,0,0,7,0,0,0,0]。
第六步:循环第二条边,n=2,m=8,parent[2]=8,打印(2,8)8,此时parent数组为:[0,0,8,0,7,0,0,0,0]。
第七步:循环第三条边,n=0,m=1,parent[0]=1,打印(0,1)10,此时parent数组为:[1,0,8,0,7,0,0,0,0]。
第八步:循环第四条边,n=1,m=5,parent[1]=5,打印(0,5)11,此时parent数组为:[1,5,8,0,7,0,0,0,0]。
循环结束后的parent数组为:
[1,5,8,7,7,8,7,0,6]。
理解克鲁斯卡尔算法:
令最小生成树的初始状态只有n个顶点而无边的非连通图,图中每个顶点自成一个连通分量。然后在边集数组中选权值最小的边加入最小生成树中,并且加入后不形成回路,否则选下一条最小权值的边,以此类推,直到生成最小生成树。(通过Fine函数记录顶点的终点,加入边时,判断该边的两个顶点的终点是否重合,重合则构成回路,否则记录其顶点的终点)
总结:克鲁斯卡尔算法适合用于边少的稀疏图,而普利姆算法适用于边多的稠密图。