大话数据结构 -07-3 最小生成树

 最小生成树

一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边。

把构造连通网的最小代价生成树称为最小的生成树。(最小成本,即n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小

经典算法:普里姆算法和克鲁斯卡尔算法

一、普里姆算法(Prim)

 初始化工作:

构造最小生成树

第一次大循环,从v0开始,找到了第一个与v0权重最小所对应的顶点,并更新了lowcost(之前记录的是邻接矩阵的第一行,大循环后更新了找到的权值最小顶点所对应的邻接矩阵的行)

k=1,lowcost[1]=0(说明该顶点加入最小生成树) 更新后:lowcost={0,0,18,65535,65535,11,16,65535,12} adjvex={0,0,1,0,0,0,1,0,1}

i=2时,min=11,k=5,lowcost[5]=0 (将顶点5加入生成树)。

连接边由(adjvex[k],k)定义,即(0,5)  其中 adjvex[5]=0。

用邻接矩阵的第五行更新lowcost={0,0,18,65535,26,0,16,65535,12} adjvex={0,0,1,0,5,0,1,0,1}

i=3时,min =12,k=8,lowcost[8]=0 (将顶点8加入生成树)。

连接边由(adjvex[k],k)定义,即(1,8)  其中 adjvex[8]=1

用邻接矩阵的第8行更新lowcost={0,0,82126,0,16,65535,0} adjvex={0,0,8,85,0,1,0,1}

 

i=4时,min =8,k=2,lowcost[2]=0 (将顶点2加入生成树)。

连接边由(adjvex[k],k)定义,即(8,2)  其中 adjvex[2]=8

用邻接矩阵的第2行更新lowcost={0,0,02126,0,16,65535,0} adjvex={0,0,8,85,0,1,0,1}   没有更新,第二行元素都比当前lowcost大

i=5时,min =16,k=6,lowcost[6]=0 (将顶点2加入生成树)。

连接边由(adjvex[k],k)定义,即(1,6)  其中 adjvex[6]=1

用邻接矩阵的第6行更新lowcost={0,0,02126,0,0190} adjvex={0,0,8,85,0,1,6,1}   

 

i=6时,min =19,k=7,lowcost[7]=0 (将顶点2加入生成树)。

连接边由(adjvex[k],k)定义,即(6,7)  其中 adjvex[7]=6

用邻接矩阵的第7行更新lowcost={0,0,0167,0,000} adjvex={0,0,8,77,0,1,6,1}   

i=7时,min =7,k=4,lowcost[4]=0 (将顶点2加入生成树)。

连接边由(adjvex[k],k)定义,即(7,4)  其中 adjvex[4]=7

用邻接矩阵的第4行更新lowcost={0,0,0160,0,000} adjvex={0,0,8,77,0,1,6,1}   

 

i=8时,min =16,k=3,lowcost[3]=0 (将顶点2加入生成树)。

连接边由(adjvex[k],k)定义,即(7,3)  其中 adjvex[3]=7

用邻接矩阵的第3行更新lowcost={0,0,000,0,000} adjvex={0,0,8,77,0,1,6,1}   

 

换一种思路理解,如下:(非常重要)有助于理解代码,为什么建立两个数组lowcost和adjvex。

二、克鲁斯卡尔算法(Kruskal)

 因为权值在边上,直接去找最小权值的边来构建生成树,但构建时要考虑是否会形成环路。

 使用边集数组存储,并按权值大小排序

定义find函数:

程序运行:

i=0; begin=4;parent[4]=0,return 4,所以n=4;end=7;parent[7]=0,return 7,所以m=7;m!=n,更新parent[4]=7; 连接边(4,7)加入生成树中

i=1; begin=2;parent[2]=0,return 2,所以n=2;end=8;parent[8]=0,return 8,所以m=8;m!=n,更新parent[2]=8; 连接边(2,8)加入生成树中

i=2; begin=0;parent[0]=0,return 0,所以n=0;end=1;parent[1]=0,return 1,所以m=1;m!=n,更新parent[0]=1; 连接边(0,1)加入生成树中

0 1 2 3 4 5 6 7 8
1 0 8 0 7 0 0 0 0

i=3; begin=0parent[0]=1>0,f=parent[0]=1,parent[1]=0;return 1,所以n=1;end=5;parent[5]=0,return 5,所以m=5;m!=n,更新parent[1]=5; 连接边(0,1)加入生成树中

(0已经与1相连,因此将与0相连的5放置再位置1)

0 1 2 3 4 5 6 7 8
1 5 8 0 7 0 0 0
0

i=4; begin=1;parent[1]=5,parent[5]=0,return 5,所以n=5;end=8;parent[8]=0,return 8,所以m=8;m!=n,更新parent[5]=8; 连接边(1,8)加入生成树中

0 1 2 3 4 5 6 7 8
1 5 8 0 7 8 0 0
0

i=5; begin=3;parent[3]=0,return 3,所以n=3;end=7;parent[7]=0,return 7,所以m=7;m!=n,更新parent[3]=7; 连接边(3,7)加入生成树中

0 1 2 3 4 5 6 7 8
1 5 8 7 7 8 0 0
0

i=6; begin=1;parent[8]=0,return 8,所以n=8;end=6;parent[6]=0,return 6,所以m=6;m!=n,更新parent[8]=6; 连接边(1,6)加入生成树中

0 1 2 3 4 5 6 7 8
1 5 8 7 7 8 0 0
6

i=7; begin=5;parent[6]=0,return 6,所以n=6;end=6;parent[6]=0,return 6,所以m=6m==n直接跳到下一个i循环。相等是因为边(5,6)形成了循环。

i=8; begin=1;parent[6]=0,return 6,所以n=6;end=2;parent[6]=0,return 6,所以m=6m==n直接跳到下一个i循环。相等是因为边(1,2)形成了循环。

i=9; begin=6;parent[6]=0,return 6,所以n=6;end=7;parent[7]=0,return 7,所以m=7;m!=n,更新parent[6]=7; 连接边(6,7)加入生成树中

0 1 2 3 4 5 6 7 8
1 5 8 7 7 8 7 0
6

此后的循环均造成环路。

 

 

posted @ 2019-03-12 10:36  GuoXinxin  阅读(685)  评论(0编辑  收藏  举报