克鲁斯卡尔算法实验报告

合集下载

求最小生成树(Kruskal算法)实验报告

求最小生成树(Kruskal算法)实验报告

求最小生成树(Kruskal算法)实验报告一、实验目的通过本次实验,掌握Kruskal算法的基本原理,能够使用该算法求解最小生成树问题,并能够进行实际应用。

同时,为学习算法的设计和分析打下基础。

二、实验内容1. 理解Kruskal算法的基本原理。

2. 实现Kruskal算法,并将其应用于求解最小生成树问题。

3. 设计实验测试用例,验证程序正确性并进行性能分析。

三、实验原理Kruskal算法是最小生成树问题的一种解决方法。

该算法基于贪心策略,通过不断选择最短的边来构造最小生成树。

实现步骤如下:1. 将所有边按权重从小到大进行排序。

2. 遍历所有边,每次选择一条没有出现在生成树中的最短边,并将该边所连接的两个顶点合并到同一连通分量中。

3. 直到所有的边都被遍历过,即可得到最小生成树。

四、实验设计本次实验的主要任务是实现Kruskal算法,并运用到最小生成树问题中。

为了测试算法的正确性和性能,需要设计适当的测试用例。

具体的实验步骤如下:1. 设计数据结构在Kruskal算法中,需要维护边的信息,并对边进行排序,同时需要维护顶点的信息。

为方便实现,可以使用C++语言的STL库中的vector和set数据结构。

vector用于存储顶点信息,set用于存储排序后的边信息。

其中,顶点包含顶点编号和连通分量编号,边包含起点、终点和边权重。

为了方便生成测试数据,定义两个常量:MAX_VERTEX和MAX_EDGE。

MAX_VERTEX表示最大顶点数量,MAX_EDGE表示最大边数量。

2. 生成测试数据为了测试算法的正确性和性能,需要生成不同大小的测试数据。

可以随机生成若干个顶点和相应的边,其中顶点编号从1开始连续编号,边的起点和终点使用随机数生成,边的权重也使用随机数生成。

3. 实现Kruskal算法根据算法原理,可以实现基本的Kruskal算法。

具体实现过程如下:1. 首先将所有的边按照权重从小到大排序,并分别初始化每个顶点的连通分量编号。

Kruskal克鲁斯卡尔最小生成树算法(贪心算法)

Kruskal克鲁斯卡尔最小生成树算法(贪心算法)

Kruskal克鲁斯卡尔最⼩⽣成树算法(贪⼼算法)1. /*2. * Introduction to Algorithms3. * Chapter 23 --- MST.Kruskal4. * Tanky Woo @ 5. * 2012.1.76. */7.8. #include <</span>iostream>9. #include <</span>algorithm>10. using namespace std;11.12. const int maxint = 999999;13.14. typedef struct Road{15. int c1, c2;// a到b16. int value;//权值17. }Road;18.19. int no;20. int line;//记录实际关系数21. Road road[100];//设⼀个⽐较⼤的值,实际看输⼊最⼩⽣成树中:边数e=n-122. int node[101];//最⼩⽣成树:n顶点数23.24. bool myCmp(const Road &a,const Road &b)25. {26. if(a.value <</span> b.value)27. return 1;28. return 0;29. }30.31. //node[2]=1 node[8]=1 ,node[3]=1,共同的祖先,如果(3,8)加进去,则构成回路,不要32. //有点像并查集33. int Find_Set(int n)34. {35. if(node[n]==-1)36. return n;37. return node[n]= Find_Set(node[n]);38. }39.40. bool Merge(int s1,int s2)41. {42. int r1 = Find_Set(s1);43. int r2 = Find_Set(s2);44. if(r1 == r2)//如果相等证明构成回路,则直接返回⼀个0,不要把顶点加进来(下⼀步是加进去的)45. return 0;46. if(r1 <</span> r2)47. node[r2]= r1;48. else49. node[r1]= r2;50. return 1;51. }52.53. int main()54. {55. freopen("input.txt","r", stdin);56. //初始化全为-157. memset(node,-1, sizeof(node));58. scanf("%d",&no);59. scanf("%d",&line);60. int i;61. for(i=0; i<</span>line; ++i)62. {63. cin >> road[i].c1 >> road[i].c2 >> road[i].value;64. }65. sort(road, road+line, myCmp);66. int sum = 0, count = 0;// sum是MST的值,count是记录已使⽤的点数67. for(i=0; i<</span>line; ++i)68. {69. if(Merge(road[i].c1, road[i].c2))//如果返回的为0,则证明构成回路,不要加进70. {71. count ++;72. sum += road[i].value;73. }74. if(count == no-1)//e=n-1已经连通,可以退出75. break;76. }77. cout <</span><</span> sum <</span><</span> endl;78. return 0;79. }80.81.82. /*83. input.txt:84. 985. 1486. 1 2 487. 1 8 888. 2 3 889. 2 8 1190. 3 4 791. 3 6 492. 3 9 293. 4 5 994. 4 6 1495. 5 6 1096. 6 7 297. 7 8 198. 7 9 699. 8 9 7100. */。

最小生成树算法实验报告

最小生成树算法实验报告

最小生成树算法实验报告【实验报告】最小生成树算法实验一、实验目的本次实验旨在研究最小生成树算法,通过对比不同的算法,并对实验结果进行分析,探索最小生成树算法的优劣势和适应场景。

二、实验过程1.算法介绍本次实验中我们将使用两种最小生成树算法:普里姆算法和克鲁斯卡尔算法。

- 普里姆算法(Prim算法):从一个顶点开始,不断在剩下的顶点中选择到当前已有的最小生成树的距离最小的边,将该边的另一个顶点加入树中,直到所有的顶点都加入树中。

- 克鲁斯卡尔算法(Kruskal算法):首先将所有边按照权值从小到大进行排序,然后以最小权值的边开始,依次选择权值最小且不会形成环路的边,直到找到n-1条边为止,其中n为顶点数。

2.实验步骤首先,我们使用Python语言实现了普里姆算法和克鲁斯卡尔算法。

然后,我们构造了一些测试用例,包括不同规模的图和不同权值分布的图。

最后,我们对实验结果进行对比分析。

三、实验结果1.测试用例设计我们设计了三个测试用例,分别为小规模图、中规模图和大规模图,具体如下:-小规模图:顶点数为5的图,权值随机分布。

-中规模图:顶点数为50的图,权值随机分布。

-大规模图:顶点数为100的图,权值随机分布。

2.实验结果分析我们的实验结果如下表所示:算法,小规模图,中规模图,大规模图:-------:,:------:,:------:,:------:普里姆算法,13,455,703从实验结果可以看出,对于小规模图和中规模图,普里姆算法的运行时间明显低于克鲁斯卡尔算法。

但是对于大规模图,克鲁斯卡尔算法的运行时间与普里姆算法的运行时间差距不大,甚至略小于普里姆算法。

这是因为克鲁斯卡尔算法中排序边的时间复杂度为O(ElogE),而普里姆算法中筛选最小距离的边的时间复杂度为O(V^2)。

综上所述,普里姆算法适用于较小规模的图,而克鲁斯卡尔算法适用于较大规模的图。

四、实验总结本次实验研究了最小生成树算法,通过对比实验结果,我们发现不同算法在不同规模的图上的表现有所差异。

2021年克鲁斯卡尔算法实验报告

2021年克鲁斯卡尔算法实验报告

实验报告试验原理:Kruskal 算法是一个根据图中边权值递增次序结构最小生成树方法。

其基础思想是: 设无向连通网为G=(V, E), 令G 最小生成树为T, 其初态为T=(V, {}), 即开始时, 最小生成树T 由图G 中n 个顶点组成, 顶点之间没有一条边, 这么T 中各顶点各自组成一个连通分量。

然后, 根据边权值由小到大次序, 考察G 边集E 中各条边。

若被考察边两个顶点属于T 两个不一样连通分量, 则将此边作为最小生成树边加入到T 中, 同时把两个连通分量连接为一个连通分量; 若被考察边两个顶点属于同一个连通分量, 则舍去此边, 以免造成回路, 如此下去, 当T 中连通分量个数为1 时, 此连通分量便为G 一棵最小生成树。

如教材153页图4.21(a)所表示, 根据Kruskal 方法结构最小生成树过程如图4.21 所表示。

在结构过程中, 根据网中边权值由小到大次序, 不停选择目前未被选择边集中权值最小边。

依据生成树概念, n 个结点生成树, 有n-1 条边, 故反复上述过程, 直到选择了n-1 条边为止, 就组成了一棵最小生成树。

试验目:本试验经过实现最小生成树算法, 使学生了解图数据结构存放表示, 并能了解最小生成树Kruskal 算法。

经过练习, 加强对算法了解, 提升编程能力。

试验内容:(1)假定每对顶点表示图一条边, 每条边对应一个权值;(2)输入每条边顶点和权值;(3)输入每条边后, 计算出最小生成树;(4)打印最小生成树边顶点及权值。

试验器材(设备、元器件):PC机一台, 装有C语言集成开发环境。

数据结构与程序:#include <iostream>#include <cstdio>#include <algorithm>using namespace std;#define X 105typedef struct Edge{int w;int x, y;} Edge; //储存边struct, 并储存边两端结点class GraphNode{public:int data;int father;int child;} GraphNode[X]; //储存点信息并查集类(点值, 父结点, 子结点)Edge edge[X*X];bool comp(const Edge, const Edge);void update(int);int main(){int node_num;int sum_weight = 0;FILE *in = fopen("C:\\Users\\瑞奇\\Desktop\\编程试验\\数据结构试验\\FileTemp\\in.txt", "r");cout << "Reading data from file..." << endl << endl;//cout << "Please input the total amount of nodes in this Graph: ";//cin >> node_num;fscanf(in, "%d", &node_num);//cout << "Please input the data of each node: " << endl;for(int i = 1;i <= node_num;i++){//cin >> GraphNode[i].data;fscanf(in, "%d", &GraphNode[i].data);GraphNode[i].father = GraphNode[i].child = i;} //初始化点集//cout << "Please input the relation between nodes in this format and end with (0 0 0):" << endl << "(first_node second_node egde_weight)" << endl;int x, y, w, tmp_cnt = 1;//while(cin >> x >> y >> w && w)while(fscanf(in, "%d%d%d", &x, &y, &w) != EOF && w)edge[tmp_cnt].w = w, edge[tmp_cnt].x = x, edge[tmp_cnt++].y = y;fclose(in);sort(edge+1, edge+tmp_cnt, comp); //对边权进行排序cout << "The MinSpanTree contains following edges: " << endl << endl;for(int i = 1;i <= tmp_cnt;i++) //循环找最小边if(GraphNode[edge[i].x].father != GraphNode[edge[i].y].father){int n = edge[i].x;int m = n;if(GraphNode[m].father != m) //使用并查集对边是否可用进行判定{m = GraphNode[m].father;GraphNode[m].father = GraphNode[edge[i].y].father;}GraphNode[edge[i].x].father = GraphNode[edge[i].y].father;GraphNode[edge[i].y].child = GraphNode[edge[i].x].child;while(GraphNode[n].child != n)n = GraphNode[n].child;update(n); //在合并点集后对并查集进行更新sum_weight += edge[i].w; //计算总权cout << "\t" << "The edge between " << GraphNode[edge[i].x].data << " & " << GraphNode[edge[i].y].data << " with the weight " << edge[i].w << endl;}cout << endl << "And the total weight of the MinSpanTree add up to: " << sum_weight << endl;return 0;}bool comp(const Edge a, const Edge b){return a.w < b.w;}void update(int n){if(GraphNode[n].father == n)return;GraphNode[GraphNode[n].father].child = GraphNode[n].child;//更新孩子结点update(GraphNode[n].father); //递归更新GraphNode[n].father = GraphNode[GraphNode[n].father].father;//更新父结点}程序运行结果:运行程序, 程序读取文件, 获取文件中相关图信息: 结点数, 结点值, 结点间边权。

数据结构-kruskal算法求最小生成树 实验报告

数据结构-kruskal算法求最小生成树 实验报告

一、问题简述题目:图的操作。

要求:用kruskal算法求最小生成树。

最短路径:①输入任意源点,求到其余顶点的最短路径。

②输入任意对顶点,求这两点之间的最短路径和所有路径。

二、程序设计思想首先要确定图的存储形式。

经过的题目要求的初步分析,发现该题的主要操作是路径的输出,因此采用边集数组(每个元素是一个结构体,包括起点、终点和权值)和邻接矩阵比较方便以后的编程。

其次是kruskal算法。

该算法的主要步骤是:GENERNIC-MIT(G,W)1. A←2. while A没有形成一棵生成树3 do 找出A的一条安全边(u,v);4.A←A∪{(u,v)};5.return A算法设置了集合A,该集合一直是某最小生成树的子集。

在每步决定是否把边(u,v)添加到集合A中,其添加条件是A∪{(u,v)}仍然是最小生成树的子集。

我们称这样的边为A 的安全边,因为可以安全地把它添加到A中而不会破坏上述条件。

然后就是Dijkstra算法。

Dijkstra算法基本思路是:假设每个点都有一对标号 (dj , pj),其中dj是从起源点s到点j的最短路径的长度 (从顶点到其本身的最短路径是零路(没有弧的路),其长度等于零);pj则是从s到j的最短路径中j点的前一点。

求解从起源点s到点j的最短路径算法的基本过程如下:1) 初始化。

起源点设置为:① ds =0, ps为空;②所有其他点: di=∞, pi=?;③标记起源点s,记k=s,其他所有点设为未标记的。

2) 检验从所有已标记的点k到其直接连接的未标记的点j的距离,并设置:d j =min[dj, dk+lkj]式中,lkj是从点k到j的直接连接距离。

3) 选取下一个点。

从所有未标记的结点中,选取dj中最小的一个i:di =min[dj, 所有未标记的点j]点i就被选为最短路径中的一点,并设为已标记的。

4) 找到点i的前一点。

从已标记的点中找到直接连接到点i的点j*,作为前一点,设置:i=j*5) 标记点i。

最小生成树克鲁斯卡尔算法

最小生成树克鲁斯卡尔算法

最小生成树克鲁斯卡尔算法
最小生成树克鲁斯卡尔算法是一种基于贪心思想的图论算法,主
要用于解决图的最小生成树问题。

该算法精简高效,在实际应用中广
泛使用。

最小生成树问题是指,在一个带权无向图中,选取一些边,使得
它们组成一棵树,且这棵树的所有边的权值之和最小。

这个问题可以
用克鲁斯卡尔算法来解决。

克鲁斯卡尔算法的思想是,首先将所有边按照权值从小到大排序,依次将每条边加入到已选的边集合中,如果加入该边后形成了环路,
则不选择该边。

最终生成的边集合就是该图的最小生成树。

这个算法的时间复杂度为O(ElogE),其中E为边数。

虽然速度不
如其他复杂度更快的算法,但克鲁斯卡尔算法的代码简洁易懂,并且
适用于边数较小的图,正因为如此,在实际应用中它的使用非常广泛。

在大型计算机网络中,最小生成树算法常用于广域网的拓扑设计
问题。

在城市交通规划中,也可以应用最小生成树算法,来设计更加
合理的交通路线。

需要注意的是,最小生成树仅仅是起到了将所有节点连接起来的
作用,它并不保证任意两个节点之间都有最短路径。

如果需要求解两
点间的最短路径问题,需要使用单源最短路径算法,如Dijkstra算法
和Bellman-Ford算法等。

总之,最小生成树克鲁斯卡尔算法在实际应用中扮演着重要的角色,尤其在计算机网络和城市规划领域的应用非常广泛。

学习并掌握这个算法,对于解决实际问题具有重要的指导意义。

图的基本操作与kruskal最小生成树实验报告

图的基本操作与kruskal最小生成树实验报告

数据结构实验五图的基本操作一、实验目的1、使学生可以巩固所学的有关图的基本知识。

2、熟练掌握图的存储结构。

3、熟练掌握图的两种遍历算法。

二、实验内容[问题描述]对给定图,实现图的深度优先遍历和广度优先遍历。

[基本要求]以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。

以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。

【测试数据】由学生依据软件工程的测试技术自己确定。

三、实验前的准备工作1、掌握图的相关概念。

2、掌握图的逻辑结构和存储结构。

3、掌握图的两种遍历算法的实现。

四、详细设计五、源程序#define INFINITY 10000#define MAX_VERTEX_NUM 40#define MAX 40#include<stdlib.h>#include<stdio.h>#include<conio.h>#include<string.h>typedef struct ArCell{int adj;}ArCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct{char name[20];}infotype;typedef struct{infotype vexs[MAX_VERTEX_NUM];AdjMatrix arcs;int vexnum,arcnum;}MGraph;int LocateVex(MGraph *G,char* v){ int c=-1,i;for(i=0;i<G->vexnum;i++)if(strcmp(v,G->vexs[i].name)==0){c=i;break;}return c;}MGraph * CreatUDN(MGraph *G)//初始化图,接受用户输入{int i,j,k,w;char v1[20],v2[20];printf("请输入图的顶点数,弧数:");scanf("%d%d",&G->vexnum,&G->arcnum);printf("结点名字:\n");for(i=0;i<G->vexnum;i++){printf("No.%d:",i+1);scanf("%s",G->vexs[i].name);}for(i=0;i<G->vexnum;i++)for(j=0;j<G->vexnum;j++)G->arcs[i][j].adj=INFINITY;printf("请输入一条边依附的两个顶点和权值:\n");for(k=0;k<G->arcnum;k++){printf("第%d条边:\n",k+1);printf("起始结点:");scanf("%s",v1);printf("结束结点:");scanf("%s",v2);printf("边的权值:");scanf("%d",&w);i=LocateVex(G,v1);j=LocateVex(G,v2);if(i>=0&&j>=0){G->arcs[i][j].adj=w;G->arcs[j][i]=G->arcs[i][j];}}return G;}int FirstAdjVex(MGraph *G,int v){int i;if(v<=0 &&v<G->vexnum){ //v合理for(i=0;i<G->vexnum;i++)if(G->arcs[v][i].adj!=INFINITY)return i;}return -1;}void VisitFunc(MGraph *G,int v){printf("%s ",G->vexs[v].name);}int NextAdjVex(MGraph *G,int v,int w){int k;if(v>=0 && v<G->vexnum && w>=0 && w<G->vexnum)//v,w合理{for( k=w+1;k<G->vexnum;k++)if(G->arcs[v][k].adj!=INFINITY)return k;}return -1;}int visited[MAX];void DFS(MGraph *G,int v)//从第v个顶点出发递归地深度优先遍历图G {int w;visited[v]=1;VisitFunc(G,v);//访问第v个结点for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))if(!visited[w]){DFS(G,w);printf("%d ",G->arcs[v][w].adj);}}void DFSTraverse(MGraph *G,char *s)//深度优先遍历{int v,k;for(v=0;v<G->vexnum;v++)visited[v]=0;k=LocateVex(G,s);if(k>=0&&k<G->vexnum){for(v=k;v>=0;v--){if(!visited[v])DFS(G,v);}for(v=k+1;v<G->vexnum;v++)if(!visited[v])DFS(G,v);}}typedef struct Qnode{int vexnum;struct Qnode *next;}QNode,*QueuePtr;typedef struct{QueuePtr front;QueuePtr rear;}LinkQueue;int InitQueue(LinkQueue *Q){Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode)); if(!Q->front)exit(0);Q->front->next=NULL;return 1;}void EnQueue(LinkQueue *Q,int a ){QueuePtr p;p=(QueuePtr)malloc(sizeof(QNode));if(!p)exit(0);p->vexnum=a;p->next=NULL;Q->rear->next=p;Q->rear=p;}int DeQueue(LinkQueue *Q,int *v){ QueuePtr p;if(Q->front==Q->rear){printf("结点不存在!\n");exit(0);}p=Q->front->next;*v=p->vexnum;Q->front->next=p->next;if(Q->rear==p)Q->front=Q->rear;return *v;}int QueueEmpty(LinkQueue *Q){if(Q->rear==Q->front)return 0;return 1;}int Visited[MAX];void BFSTraverse(MGraph *G,char *str)//广度优先遍历{int w,u,v,k;LinkQueue Q,q;for(v=0;v<G->vexnum;v++) Visited[v]=0;InitQueue(&Q);InitQueue(&q);k=LocateVex(G,str);for(v=k;v>=0;v--)if(!Visited[v]){Visited[v]=1;VisitFunc(G,v);EnQueue(&Q,v);//v入队while(!QueueEmpty(&Q)){DeQueue(&Q,&u);//出队for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w)) if(!Visited[w]){Visited[w]=1;VisitFunc(G,v);EnQueue(&Q,w);}}}for(v=k+1;v<G->vexnum;v++)if(!Visited[v]){Visited[v]=1;VisitFunc(G,v);EnQueue(&Q,v);//v入队while(!QueueEmpty(&Q)){DeQueue(&Q,&u);//出队for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w)) if(!Visited[w]){Visited[w]=1;VisitFunc(G,v);EnQueue(&Q,w);}}}}void main(){MGraph *G,b;char v[10];G=CreatUDN(&b);printf("请输入起始结点名称:");scanf("%s",v);printf("\n深度优先遍历:\n");DFSTraverse(G,v);printf("\n广度优先遍历:\n");BFSTraverse(G,v);getch();}六、测试数据及调试实验六图的应用一、实验目的1、使学生可以巩固所学的有关图的基本知识。

离散数学--最小生成树实验报告

离散数学--最小生成树实验报告

创作编号:GB8878185555334563BT9125XW创作者:凤呜大王*一、实验目的:掌握图的存储表示和以及图的最小生成树算法。

二、实验内容:1.实现图的存储,并且读入图的内容。

2.利用克鲁斯卡尔算法求网络的最小生成树。

3.实现构造生成树过程中的连通分量抽象数据类型。

4.以文本形式输出对应图的最小生成树各条边及权值。

三、实验要求:1.在上机前写出全部源程序;2.能在机器上正确运行程序;3.用户界面友好。

需求分析:1、利用克鲁斯卡尔算法求网的最小生成树;2、以用户指定的结点为起点,分别输出每种遍历下的结点访问序列;3、输入为存在边的顶点对,以及它们之间的权值;输出为所得到的邻接矩阵以及按权排序后的边和最后得到的最小生成树;克鲁斯卡尔算法:假设WN=(V,{E}) 是一个含有n 个顶点的连通网,按照构造最小生成树的过程为:先构造一个只含n 个顶点,而边集为空的子图,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。

依次类推,直至只有一棵树,也即子图中含有n-1条边为止。

测试数据:自行指定图进行运算四、详细设计源程序#include<stdio.h>#include<stdlib.h>#define M 20#define MAX 20typedef struct{int begin;int end;int weight;}edge;typedef struct{int adj;int weight;}AdjMatrix[MAX][MAX];typedef struct{AdjMatrix arc;int vexnum, arcnum;}MGraph;void CreatGraph(MGraph *);void sort(edge* ,MGraph *);void MiniSpanTree(MGraph *);int Find(int *, int );void Swapn(edge *, int, int);void CreatGraph(MGraph *G)创作编号:GB8878185555334563BT9125XW创作者:凤呜大王*{int i, j,n, m;printf("请输入边数和顶点数:");scanf("%d %d",&G->arcnum,&G->vexnum);for (i = 1; i <= G->vexnum; i++){for ( j = 1; j <= G->vexnum; j++){G->arc[i][j].adj = G->arc[j][i].adj = 0;}}for ( i = 1; i <= G->arcnum; i++){printf("\n请输入有边的2个顶点");scanf("%d %d",&n,&m);while(n < 0 || n > G->vexnum || m < 0 || n > G->vexnum){printf("输入的数字不符合要求请重新输入:");scanf("%d%d",&n,&m);}G->arc[n][m].adj = G->arc[m][n].adj = 1;getchar();printf("\n请输入%d与%d之间的权值:", n, m);scanf("%d",&G->arc[n][m].weight);}printf("邻接矩阵为:\n");for ( i = 1; i <= G->vexnum; i++){for ( j = 1; j <= G->vexnum; j++){printf("%d ",G->arc[i][j].adj);}printf("\n");}}void sort(edge edges[],MGraph *G){int i, j;for ( i = 1; i < G->arcnum; i++){for ( j = i + 1; j <= G->arcnum; j++){if (edges[i].weight > edges[j].weight){Swapn(edges, i, j);}}}printf("权排序之后的为:\n");for (i = 1; i < G->arcnum; i++){printf("<< %d, %d >> %d\n", edges[i].begin, edges[i].end, edges[i].weight);}}void Swapn(edge *edges,int i, int j){创作编号:GB8878185555334563BT9125XW创作者:凤呜大王*int temp;temp = edges[i].begin;edges[i].begin = edges[j].begin;edges[j].begin = temp;temp = edges[i].end;edges[i].end = edges[j].end;edges[j].end = temp;temp = edges[i].weight;edges[i].weight = edges[j].weight;edges[j].weight = temp;}void MiniSpanTree(MGraph *G){int i, j, n, m;int k = 1;int parent[M];edge edges[M];for ( i = 1; i < G->vexnum; i++){for (j = i + 1; j <= G->vexnum; j++) {if (G->arc[i][j].adj == 1){edges[k].begin = i;edges[k].end = j;edges[k].weight = G->arc[i][j].weight;k++;}}}sort(edges, G);for (i = 1; i <= G->arcnum; i++){parent[i] = 0;}printf("最小生成树为:\n");for (i = 1; i <= G->arcnum; i++){n = Find(parent, edges[i].begin);m = Find(parent, edges[i].end);if (n != m){parent[n] = m;printf("<< %d, %d >> %d\n", edges[i].begin, edges[i].end, edges[i].weight);}}}int Find(int *parent, int f){while ( parent[f] > 0){f = parent[f];}return f;}int main(void){MGraph *G;G = (MGraph*)malloc(sizeof(MGraph));if (G == NULL){printf("memory allcation failed,goodbye");exit(1);}CreatGraph(G);创作编号:GB8878185555334563BT9125XW创作者:凤呜大王*MiniSpanTree(G);system("pause");return 0;}运行结果:五、实验总结(结果分析和体会)在编程时,因为考虑的情况比较多,所以容易造成错误和遗漏,为了避免这些问题的出现,可以先用笔把所有的程序在纸上,然后再根据列表编写程序,这样不仅简单易懂,还避免了一些不必要的错误。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验报告
实验原理:
Kruskal 算法是一种按照图中边的权值递增的顺序构造最小生成树的方法。

其基本思想是:设无向连通网为G=(V,E),令G 的最小生成树为T,其初态为T=(V,{}),即开始时,最小生成树T 由图G 中的n 个顶点构成,顶点之间没有一条边,这样T 中各顶点各自构成一个连通分量。

然后,按照边的权值由小到大的顺序,考察G 的边集E 中的各条边。

若被考察的边的两个顶点属于T 的两个不同的连通分量,则将此边作为最小生成树的边加入到T 中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T 中的连通分量个数为1 时,此连通分量便为G 的一棵最小生成树。

如教材153页的图4.21(a)所示,按照Kruskal 方法构造最小生成树的过程如图 4.21 所示。

在构造过程中,按照网中边的权值由小到大的顺序,不断选取当前未被选取的边集中权值最小的边。

依据生成树的概念,n 个结点的生成树,有n-1 条边,故反复上述过程,直到选取了n-1 条边为止,就构成了一棵最小生成树。

实验目的:
本实验通过实现最小生成树的算法,使学生理解图的数据结构存储表示,并能理解最小生成树Kruskal 算法。

通过练习,加强对算法的理解,提高编程能力。

实验内容:
(1)假定每对顶点表示图的一条边,每条边对应一个权值;
(2)输入每条边的顶点和权值;
(3)输入每条边后,计算出最小生成树;
(4)打印最小生成树边的顶点及权值。

实验器材(设备、元器件):
PC机一台,装有C语言集成开发环境。

数据结构与程序:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define X 105
typedef struct Edge
{
int w;
int x, y;
} Edge; //储存边的struct,并储存边两端的结点
class GraphNode
{
public:
int data;
int father;
int child;
} GraphNode[X]; //储存点信息的并查集类(点的值,父结点,子结点)Edge edge[X*X];
bool comp(const Edge, const Edge);
void update(int);
int main()
{
int node_num;
int sum_weight = 0;
FILE *in = fopen("C:\\Users\\瑞奇\\Desktop\\编程实验\\数据结构实验\\FileTemp\\in.txt", "r");
cout << "Reading data from file..." << endl << endl;
//cout << "Please input the total amount of nodes in this Graph: ";
//cin >> node_num;
fscanf(in, "%d", &node_num);
//cout << "Please input the data of each node: " << endl;
for(int i = 1;i <= node_num;i++)
{
//cin >> GraphNode[i].data;
fscanf(in, "%d", &GraphNode[i].data);
GraphNode[i].father = GraphNode[i].child = i;
} //初始化点集
//cout << "Please input the relation between nodes in this format and end with (0 0 0):" << endl << "(first_node second_node egde_weight)" << endl;
int x, y, w, tmp_cnt = 1;
//while(cin >> x >> y >> w && w)
while(fscanf(in, "%d%d%d", &x, &y, &w) != EOF && w)
edge[tmp_cnt].w = w, edge[tmp_cnt].x = x, edge[tmp_cnt++].y = y;
fclose(in);
sort(edge+1, edge+tmp_cnt, comp); //对边权进行排序
cout << "The MinSpanTree contains following edges: " << endl << endl;
for(int i = 1;i <= tmp_cnt;i++) //循环找最小边
if(GraphNode[edge[i].x].father != GraphNode[edge[i].y].father)
{
int n = edge[i].x;
int m = n;
if(GraphNode[m].father != m) //使用并查集对边是否可用进行判断
{
m = GraphNode[m].father;
GraphNode[m].father = GraphNode[edge[i].y].father;
}
GraphNode[edge[i].x].father = GraphNode[edge[i].y].father;
GraphNode[edge[i].y].child = GraphNode[edge[i].x].child;
while(GraphNode[n].child != n)
n = GraphNode[n].child;
update(n); //在合并点集后对并查集进行更新
sum_weight += edge[i].w; //计算总权
cout << "\t" << "The edge between " << GraphNode[edge[i].x].data << " & " << GraphNode[edge[i].y].data << " with the weight " << edge[i].w << endl;
}
cout << endl << "And the total weight of the MinSpanTree add up to: " << sum_weight << endl;
return 0;
}
bool comp(const Edge a, const Edge b)
{
return a.w < b.w;
}
void update(int n)
{
if(GraphNode[n].father == n)
return;
GraphNode[GraphNode[n].father].child = GraphNode[n].child;
//更新孩子结点update(GraphNode[n].father); //递归更新
GraphNode[n].father = GraphNode[GraphNode[n].father].father;
//更新父结点
}
程序运行结果:
运行程序,程序读取文件,获取文件中关于图的信息:结点数,结点值,结点间边权。

然后使用Kruskal算法对录入信息进行处理:
1.对边权排序
2.取最小权边,若边的端结点不在同一集合众,则使边的端结点加入集合并删除该边;若边的端结点本来就在同一集合中,直接删除该边
3.循环执行步骤2,直到集合中包含所有结点和结点数-1条边
输入为:
6
1 2 3 4 5 6
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
程序运行结果如下图:
实验结论:
Kruskal算法其实是一种贪心算法,每次选取符合条件的边,加入边集(此程序中直接输出)。

直到所有结点和最少边全部包含在同一集合中,算法结束。

总结及心得体会:
在使用并查集的时候,注意在合并集合后要更新并查集的父结点和子结点。

其实Kruskal算法的复杂度为O(E^2),其复杂度和边条数有关,和结点数无关,所以适用于稀疏图。

相关文档
最新文档