码迷,mamicode.com
首页 > 其他好文 > 详细

数据结构(构造连通网的最小生成树)

时间:2020-05-10 01:33:19      阅读:250      评论:0      收藏:0      [点我收藏+]

标签:操作   之间   另一个   邻接   连接   div   打印   下标   中心   

普利姆算法

  形象问题:几个村庄之间有N条路,要再路边修下水管道,求在那些路上修管道能在全部村庄连通的基础上使修的管道最短

  中心思想:从一个顶点逐渐连接到全部顶点;在连接过程中找权最小的边加入生成树中

方法

  • 规定从第一个结点出发,找到连接的边中权最小的
  • 将这条边加入生成树中
  • 循环①,②步,不断找到连接一个顶点的权最小的边,直到连接玩全部顶点
  • 顶点和这些边就构成了连通网的最小生成树

技术图片

 1 //G是一个图结构体:
 2 //numVertexes:顶点个数
 3 //arc:邻接矩阵
 4 void MinSpanTree_prim(MGraph G){
 5     int min , i , j , k;
 6     int adjvax[MAXVEX];//到该位置对应顶点的最短路径的边的另一个顶点【方便找到边后打印这条边的两个顶点下标】
 7     int lowcost[MAXVEX];//连接到下标对应顶点的边的最小权【为0表示已经找到;INFINITY表示还没找到;其他表示:目前为止的值】
 8             //既然说是目前为止,是因为以后连接到其他顶点,还会添加可选择的边;在这些新加的边中可能会刷新连接它的边的权最小记录
 9 
10     lowcost[0]=0;//第一个顶点作为最小生成树的根,权直接为0
11     adjvax[0]=0;//第一个顶点先加入
12 
13     //初始化操作
14     for(i=1;i<G.numVertexes;i++){
15         lowcost[i]=G.arc[0][i];//将邻接矩阵第0行所有权值加入数组(从第一个顶点开始到其他顶点的权)
16         adjvax[i]=0;//初始化全部为第一个顶点的下标
17     }
18 
19     //开始构建最下生成树
20     for(i=1;i<G.numVertexes;i++){//连接N个顶点,找N-1条边,分别从一个顶点找到其他N-1个顶点
21         min = INFINITY;//记录最小权值;初始化为65535;
22         j=1;//循环使用的索引值
23         k=0;//记录这次连接到的顶点的下标
24 
25         //遍历全部顶点
26         while(j<G.numVertexes){//找到可连接的最小权
27             if(lowcost[j]!=0 && lowcost[j]<min){
28                 min=lowcost[j];
29                 k=j;//将找到的最小权值下标存入k;
30             }
31             j++;
32         }
33 
34         printf("(%d,%d)  ",adjcex[k],k);//打印当前顶点边中权值最小的边;adjcex[k],边的起始下标;k,当前位置
35         lowcost[k]=0;//将当前顶点的权值设置为0,表示此顶点已经连接到生成树中,继续进行连接下一个顶点
36 
37         //邻接矩阵k行逐个遍历全部顶点
38         for(j=1;j<G.numVertexes;j++){
39             if(lowcost[j]!=0 && G.[k][j] < lowcost[j]){
40                 lowcost[j]=G.arc[k][j];//刚刚连接的顶点下标k,连接到j位置顶点的权小于原先连接到j位置的权;那么就刷新连接他的最小权
41                 adjvax[j]=k;//将刷新连接j位置最小权的顶点的下标记录到adjvax数组j位置下;利用该值打印这条权最小记录的边:(adjvax[k],k)
42             }
43         }
44     }
45 }

克鲁斯卡尔算法

  直接去找权最小的边来构建生成树(构建过程中只要避免构成环即可)

方法

  • 将图中所有边以权排序成边集,图中顶点去掉全部边(构成树林)
  • 遍历边集数组,检测每条边依附的两顶点是否在同一颗树中【不在的话连接两顶点(树)组成一颗树;若在连接后就会构成环,所以舍弃这种边】
  • 遍历完边集数组时就构造出了最小生成树

技术图片

 1 int find(int *parent,int f){
 2     while(parent[f]>0){
 3         f=parent[f];
 4     }
 5     return f;
 6 }
 7 //parent数组:存储当前位置对应顶点在一棵树上的另一个顶点的对应下标
 8     //所以刚开始时,存储下标对应的顶点是与自身位置对应顶点是直接相连的
 9     //当这个位置构建最小生成树会直接相连一个顶点以上时,那么下一个连接顶点下标会存储在第一个连接下标顶点对应位置
10     //例如:0下标顶点构建最小生成树时会连接1下标和3下标两个顶点对应位置顶点;那么:parent[0]=1;parent[1]=3;或者parent[0]=3;parent[3]=1
11 //总之parent数组中将同一颗树顶点的下标利用类似链表的方法连接在一起;
12     //给f传入一颗树任意顶点对应的下标返回的值(x)都是一样的;并且在parent[x]这个位置是存放这颗树下一次新加的顶点下标的
13 
14 //Kruskal算法生成最小生成树
15 void MiniSpanTree_Kruskal(MGraph G){
16     int i,n,m;
17     Edge edges[MAGEDGE];//定义边集数组
18     int parent[MAGEDGE];//定义parent数组用来判断边与边是否形成环路
19 
20     for(i=0;i<G.numVertexes;i++){
21         parent[i]=0;
22     }
23     for(i=0;i<G.numEdges;i++){
24         //edges:边集数组;边的结构:begin,起点;end,终点;weight,这条边的权
25         //n得到的是edges[i].begin这个下标所属树下一次新加顶点下标在prent数组中存储位置
26         //m得到的值也有edges[i].end顶点所属树的相同作用
27         //所以m==n就说明两顶点属于同一颗树(已经间接连接了,不需要再重复直接连接了;也就是不要形成环路)
28         //只有所属不同树时才同时有添加的能力,合并两棵树相当于要用掉一棵树的添加能力,合并后的数的添加能力就要原先被添加树承担
29         n=find(parent,edges[i].begin);
30         m=find(parent,edges[i].end);
31         if(n!=m){//如果n==m,则形成环路
32             parent[n]=m;//将此边的结尾顶点放入下标起点的parent数组中,表示此顶点已经在生成树集合中
33             printf("(%d,%d)%d  ",edges[i].begin,edges[i].end,edges[i].weight);
34         }
35     }
36 }

 

数据结构(构造连通网的最小生成树)

标签:操作   之间   另一个   邻接   连接   div   打印   下标   中心   

原文地址:https://www.cnblogs.com/TianLiang-2000/p/12861241.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!