最小生成树问题中北大学数据结构课程设计资料
课程设计-最小生成树

最小生成树1. 任务与需求该课程设计要求从从给定一个地图,包括若干城市间道路的距离,用Prim算法或者Kruskal算法建立最小生成树,求出最小生成树的代价。
用邻接矩阵来表示图。
根据分析,该课程设计需要完成的具体功能有:(1) 能够创建图;(2) 为了方便使用,可以把输入的图保存到数据文件中;(3) 能够读取数据文件中图的信息,创建图;(4) 能够显示最小生成树,包括起始和终点的序号以及最小生成树的代价。
图1 给定的图2. 总体设计对于一个无相连通图G=(V,E),设G’是它的一个子图,如果G’满足下列条件:(1) G’中包含了G中所有顶点,即V(G’)=V(G);(2) G’是连通图;(3) G’中无回路。
则称G’是G的一棵生成树。
如果无相连通图是一个网,那么它的所有生成树中必有一棵边的权值总和最小的生成树,则称这棵生成树是最小代价生成树,简称为最小生成树。
最小生成树的概念可以应用到许多实际问题,例如:计算城市之间道路构造问题,要想使总的造价最低,实际上就是寻找该网络的最小生成树。
根据任务与需求,该程序需要能够输入数据、保存文件、读取文件、创建图、显示最小生成树。
最小生成树的常用算法有两种,分别使用这两种方法进行最小生成树的计算。
系统功能模块如图:图2 系统功能模块图3. 详细设计3.1 最小生成树算法常见的两种构造最小生成树的算法是Prim算法和Kruskal算法。
1. Prim算法假设G=(V,E)为一网络,其中V为网络中的顶点集合,E为网络中的所有带权边集合。
设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,集合T存放G的最小生成树的边。
令集合U的初值为U={u0}(假设从u0出发),集合T的初值为T={}。
从所有u∈U,v∈V-U两个顶点构成的边中,选取具有最小权值的边(u,v),将顶点v加入集合U中,将边(u,v)加入集合T中。
如此不断重复,直到U=V时,最小生成树构造完毕,这时候集合T中包含了最小生成树的所有边。
数据结构课程设计报告(最小生成树完整版)

武夷学院课程设计报告课程名称:数据结构设计题目:最小生成树的应用学生班级:09计科2班学生姓名:蒋家权,陈相财,吴继伟,梁丽春指导教师:林丽惠完成日期:2011-1-19课程设计项目研究报告目录一、问题分析和任务定义....................................................................................... - 1 -二、实现本程序需要解决的问题如下................................................................... - 1 -三、测试数据........................................................................................................... - 2 -四、算法思想........................................................................................................... - 3 -五、模块划分........................................................................................................... - 4 -六、算法设计与分析............................................................................................... - 7 -七、源程序............................................................................................................. - 11 -八、测试数据......................................................................................................... - 14 -九、课程设计项目进度表及任务分配表及任务分配表..................................... - 16 -十、设计心得......................................................................................................... - 17 -十、参考书目......................................................................................................... - 18 -一、问题分析和任务定义在n个城市间建立通信网络,需架设n-1条线路。
大数据结构课程设计-最小生成树

《数据结构》期末课程设计题目第8题:最小生成树问题学院计算机学院专业班别学号姓名陈聪2015年7月6日一、需求分析1、问题描述若要在n个城市之间建设通讯网络,只需要架设n-1条线路即可。
如何以最低的经济代价建设这个通讯网,是一个网的最小生成树问题。
2、基本要求(1)利用克鲁斯卡尔算法求网的最小生成树。
(2)实现并查集。
以此表示构造生成树过程中的连通分量。
(3)以文本形式输出生成树中各条边以及他们的权值。
3、实现提示通讯线路一旦建立,必然是双向的。
因此,构造最小生成树的网一定是无向网。
设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数,可利用C语言提供的随机数函数产生。
图的存储结构的选取应和所作操作向适应。
为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组即边集数组表示图。
二、详细设计根据课设题目要求,拟将整体程序分为三大模块,分别是:图的存储结构,并查集的实现,克鲁斯卡尔算法的实现。
1、边集数组的类型定义:typedef struct{int x, y;int w;}edge;x表示起点,y表示终点,w为权值。
2、并查集功能的实现由以下函数实现:Make_Set(int x)初始化集合;Find_Set(int x) 查找x元素所在的集合,回溯时压缩路径;Union(int x, int y, int w)合并x,y所在的集合。
3、克鲁斯卡尔算法的实现该算法的实现位于主函数中:qsort(e, n, sizeof(edge), cmp); //将边排序printf("最小生成树的各条边及权值为:\n");for (i = 0; i < n; i++){x = Find_Set(e[i].x);y = Find_Set(e[i].y);if (x != y ){printf("%c - %c : %d\n", e[i].x + 'A', e[i].y + 'A', e[i].w);Union(x, y, e[i].w);}}4、设计中还包含以下函数:(1)/* 比较函数,按权值(相同则按x坐标)非降序排序*/ int cmp(const void *a, const void *b){if ((*(edge *)a).w == (*(edge *)b).w){return (*(edge *)a).x - (*(edge *)b).x;}return (*(edge *)a).w - (*(edge *)b).w;}(2)快排函数qsort,包含在stdlib.h头文件里qsort(e, n, sizeof(edge), cmp);(3)C语言提供的随机数函数srand( unsigned int seed );使用随机数函数如下:srand( (unsigned)time( NULL ) );for( i = 0; i < n;i++ ){e[i].w=rand()%100+1;e[i].x = chx - 'A';if(chy==h+48) chx++;e[i].y = (chy++) - 'A';if(chy==h+49) chy=chx+1;Make_Set(i);}输出1~100之间的随机数,使用rand()%100+1。
数据结构课程设计报告---最小生成树问题

二○一○届课程设计论文《算法与数据结构》二〇一〇年六月目录一、引言…………………………………………二、设计目的与任务………………………………1·课程设计的目的2·课程设计的任务三、设计方案………………………………………1·需求分析2·概要设计3·详细设计4·程序清单四、调试分析………………………………………五、测试结果………………………………………六、附录……………………………………………七、工作环境………………………………………八、参考文献……………………………《数据结构》课程设计——最小生成树问题一、引言《数据结构》是计算机科学与技术专业和信息系统专业的必修课之一,是一门综合的专业技术课。
本课程较系统的介绍了软件开发过程中常用的数据结构及相应的实现算法。
如线性表、栈、队列、树和二叉树,图、检索和排列等,并对性能进行分析和比较,内容非常丰富。
本课程设计我们要解决的是最小生成树问题。
要用到图的相关数据结构和最小生成树的克鲁斯卡尔算法,以及存储图的边和点的邻接矩阵。
本课程设计要解决的问题是构造连通图的最小生成树我们首先要做的是都造一个邻接表,用以存储图,然后我们要想好怎样利用克鲁斯卡尔算法构造最小生成树,把这个算法写入主程序,调试好程序,最后完成报告。
二、设计目的与任务1·课程设计的目的本课程设计是为了了解并掌握数据结构及算法的设计方法,具备初步的独立分析和设计能力;初步掌握软件开发过程的相关步骤;提高运用所学理论知识独立分析和解决问题的能力;训练用系统的观点和软件开发的一般规范进行软件开发。
2·课程设计的任务问题描述:若要在n个城市之间建设通信网络,只需架设n—1条线路即可。
如何以最低的经济代价建设这个通信网,是一个最小生成树的问题。
三、设计方案1·需求分析(1)利用克鲁斯卡尔算法求最小生成树;(2)实现教科书6.5节中抽象数据类型MFSet。
数据结构实验报告十二—最小生成树问题

问题描述:若要在n个城市之间建设通信网络,只需要架设n-1条线路即可。
如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
一、需求分析:需定义结构体数组,根据权值逐一选择边。
二、概要设计:抽象数据类型:需定义结构体数组,存储每条边的起点,终点,权值。
算法的基本思想:1、图的信息的读取:定义结构体数组,存储每条边的起点,终点,权值。
2、对每条边在数组中的位置处理:选边需从最小的开始,故按边的权值从小到大进行排序。
3、边的选取:从最小的边的开始,若边的两端点不属于同一集合,则选取该边。
并将该边的两个顶点所在的两个集合合并成为一个。
因为有n个顶点,故只需选取n-1条边。
程序的流程程序由三个模块组成:输入模块:读入图的信息(顶点和边,用结构体数组进行存储)。
处理模块:Kruskal算法。
输出模块:将结果输出。
三、详细设计算法的具体步骤:struct G{int fromvex;int endvex;int weight;}GE[100],cur[100];void swap(G* GE,int i,int j){ //交换函数int temp=GE[i].fromvex;GE[i].fromvex=GE[j].fromvex;GE[j].fromvex=temp;temp=GE[i].endvex;GE[i].endvex=GE[j].endvex;GE[j].endvex=temp;temp=GE[i].weight;GE[i].weight=GE[j].weight;GE[j].weight=temp;}void Kruskal(int n){int i,j,k=0,pos=-1,m1,m2;bool** s=new bool *[n];//定义一个二维数组,用来判断是否为同一类for(i=0;i<n;i++)s[i]=new bool[n];for(i=0;i<n;i++){for(j=0;j<n;j++){if(i==j)s[i][j]=true; //初始化数组elses[i][j]=false;}}while(k<n-1){for(i=0;i<n;i++){if(s[i][GE[k].fromvex]==1)m1=i;if(s[i][GE[k].endvex]==1)m2=i;}if(m1!=m2){//判断是否为同一类,如果为同一类(该类中所有的点到起点和终//点的边在s数组中赋为1),cur[++pos].fromvex=GE[k].fromvex;cur[pos].endvex=GE[k].endvex;cur[pos].weight=GE[k].weight;for(i=0;i<n;i++){if(s[m1][i] || s[m2][i])//把该点添加到该类,并和并两个类s[m1][i]=1;elses[m1][i]=0;s[m2][i]=0;}}k++;}for(i=0;i<n;i++){delete []s[i];}}int main(){int i,j;int numVertex,numEdge;cout<<"请输入点的个数和边的条数:"<<endl;cin>>numVertex>>numEdge;cout<<"请输入边的起始位置和边的权值:"<<endl;for(i=0;i<numEdge;i++)cin>>GE[i].fromvex>>GE[i].endvex>>GE[i].weight;for(i=0;i<numEdge;i++)for(j=i;j<numEdge;j++){if(GE[j].weight<GE[i].weight)//将边的权值按从小到大排列swap(GE,i,j);}Kruskal(numEdge);for(i=0;i<numVertex-1;i++)cout<<cur[i].fromvex<<"->"<<cur[i].endvex<<":"<<cur[i].weight<<endl; system("pause");return 0;}四、调试分析:将选边的过程输出来检验算法的正确性。
最小生成树-课程设计报告

课程设计报告问题描述:已知一个无向连通网表示n个城市以及城市间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边上的权值表示相应的代价。
对于n个点的连通网能建立许多不同的生成树,每一棵生成树都可以是一个通信网。
我们要选择一棵生成树,使总的耗费最小(1)需求分析:在N地建设网络保证连通即可求最小的架设方式,任务完成可分为两个部分:A 存储N中任意两地之间的权(采用邻接表,邻接矩阵)B 用prim和克鲁斯卡尔两种算法分别求出N地中最优架设方式即最小生成树。
C 按顺序输出生成树中各条边以及它们的权值。
(2)概要设计:程序分为两大部分 1 存储部分,2 算法部分;存储部分分为邻接矩阵和邻接表,而且包含了两者直接的互相转换;算法部分分为普里母算法和克鲁斯卡尔算法。
Prim算法的思想:假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:1:初始化:U={u 0},TE={f}。
此步骤设立一个只有结点u 0的结点集U 和一个空的边集TE作为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到得到最小生成树为止。
2:在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。
此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。
找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。
这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。
3:如果U=V,则算法结束;否则重复步骤2。
可以把本步骤看成循环终止条件。
我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。
最小生成树问题课程设计

最小生成树问题课程设计一、课程目标知识目标:1. 理解最小生成树的概念,掌握其定义及性质;2. 学会运用普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法求解最小生成树问题;3. 了解最小生成树在实际问题中的应用,如网络设计、电路设计等。
技能目标:1. 能够运用普里姆和克鲁斯卡尔算法解决最小生成树问题,并进行算法分析;2. 能够运用所学知识解决实际问题,具备一定的算法设计能力;3. 能够通过合作与交流,提高问题分析和解决问题的能力。
情感态度价值观目标:1. 培养学生对数据结构与算法的兴趣,激发学习热情;2. 培养学生的团队合作意识,学会倾听、尊重他人意见;3. 培养学生面对问题勇于挑战、积极进取的精神。
课程性质:本课程为计算机科学与技术专业的高年级课程,旨在帮助学生掌握图论中的最小生成树问题及其求解方法。
学生特点:学生具备一定的编程基础和图论知识,对算法有一定的了解,但可能对最小生成树问题尚不熟悉。
教学要求:结合学生特点,采用案例教学、任务驱动等方法,注重理论与实践相结合,培养学生的实际操作能力和创新思维。
通过本课程的学习,使学生能够将所学知识应用于实际问题中,提高解决复杂问题的能力。
二、教学内容1. 最小生成树概念与性质- 定义、性质及定理- 最小生成树的构建方法2. 普里姆算法- 算法原理与步骤- 算法实现与复杂度分析- 举例应用3. 克鲁斯卡尔算法- 算法原理与步骤- 算法实现与复杂度分析- 举例应用4. 最小生成树在实际问题中的应用- 网络设计- 电路设计- 其他领域应用案例5. 算法比较与优化- 普里姆与克鲁斯卡尔算法的比较- 算法优化方法及其适用场景6. 实践环节- 编程实现普里姆和克鲁斯卡尔算法- 分析并解决实际问题- 小组讨论与成果展示教学内容依据课程目标进行选择和组织,注重科学性和系统性。
参考教材相关章节,制定以下教学安排:第1周:最小生成树概念与性质第2周:普里姆算法第3周:克鲁斯卡尔算法第4周:最小生成树在实际问题中的应用第5周:算法比较与优化第6周:实践环节与总结三、教学方法本课程将采用以下多样化的教学方法,以激发学生的学习兴趣和主动性:1. 讲授法:教师通过生动的语言和形象的比喻,对最小生成树的概念、性质、算法原理等基础知识进行讲解,使学生快速掌握课程内容。
数据结构课程设计报告(最小生成树)

《数据结构》课程设计报告课程名称:最小生成树课题负责人名(学号):同组成员名单(角色):指导教师:评阅成绩:评阅意见:提交报告时间:2011年12月19日最小生成树计算机科学与技术专业学生:指导老师:[摘要]选择一颗生成树,使之总的消费最少,也就是要构造连通网的最小代价生成树(简称为最小生成树)的问题,一颗生成树的代价就是树上各边的代价之和,构造最小生成树可以有多种算法,其中多数算法利用了MST的性质。
关键词:最小生成树连通图普里姆算法克鲁斯卡尔算法 MST一、设计目的1.了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
二、算法思想分析该设计的要求是在n个城市之间建设网络,不仅要保证连通,还要求是最经济的架设方法。
根据克鲁斯卡尔和普里姆算法的不同之处,该程序将城市个数大于十个时应用普里姆算法求最小生成树,而城市个数小于十个时则应用克鲁斯卡尔进行计算。
1.算法思想1)普里姆(Prim)算法思想a)选择从0节点开始,并选择0节点相关联的最小权值边,将与这条边相关联的另一顶点出列;b)在出列的节点中相关联的所有边中选择一条不与另一个已出列的节点相关联的权值最小的边,并将该边相关联的节点出列;c)重复b)直到所有的节点出列。
2)克鲁斯卡尔(Kruskal)算法思想为了使生成树上总的权值之和最小,应该使每一条边上的权值尽可能的小,所以应从权值最小的边选起,直至选出n-1条不能构成回路的权值最小的边位置。
具体做法如下:首先构造一个含n个顶点的森林,然后按权值从小到大从连通图中选择不使森林中产生回路的边加入到森林中去,直至该森林变成一棵树为止,这棵树便是连通图的最小生成树。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
中北大学数据结构与算法课程设计说明书学院、系:软件学院专业:软件工程班级:学生姓名:学号:设计题目:最小生成树问题起迄日期: 2015年1月12日- 2015年1月29日指导教师:王秀娟2015 年1月 29 日1需求分析1.1已知一个无向连通网表示n个城市以及城市间可能设置的通信网络线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边上的权值表示相应的代价。
对于n个点的连通网能建立许多不同的生成树,每一棵生成树都可以是一个通信网。
我们要选择一棵生成树,使总的耗费最小。
1.2该无向连通图的建立需要使用两种存储结构,即邻接表和邻接矩阵。
1.3实现最小生成树需要使用两种算法。
即普里姆算法和克鲁斯卡尔。
1.4程序通过人机交互实现数据的输入和输出。
2选题要求设计内容:在n个城市之间建设网络,只需保证连通即可,求最经济的架设方法。
存储结构采用(邻接表和邻接矩阵)两种,采用课本上的两种求解算法。
设计要求:(1) 符合课题要求,实现相应功能;(2) 要求界面友好美观,操作方便易行;(3) 注意程序的实用性、安全性。
3程序设计方法及主要函数介绍ADT Graph{数据对象V;V是具有相同特性的数据元素的集合,成为顶点集。
数据关系R:R = {VR}VR = {(v,w)|v,w为V集合中的元素,(v,w)表示v和w之间存在的路径} 基本操作P;CreateMGraph(MGraph *G)初始条件:V是图的顶点集,VR是图的边的集合。
操作结果:按V和VR的定义构造图G,用邻接矩阵存储。
CreateALGraph(ALGraph *G)初始条件:V是图的顶点集,VR是图的边的集合。
操作结果:按V和VR的定义构造图G,用邻接表存储。
LocateVex(G,u)初始条件:图G存在,u和G中顶点有相同的特征。
操作结果:若G中存在顶点u,则返回该顶点在图中的位置;否则返回其他信息。
MiniSpanTree_PRIM(G, u)初始条件:图G存在,u是图G中的一个顶点。
操作结果:用普利姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边。
Kriuskal(G)初始条件:图G存在操作结果:用克鲁斯卡尔算法构造图G的最小生成树T,输出T的各条边。
ListToMat(MGraph *G1,ALGraph *G2)初始条件:图G2存在操作结果:把图的邻接表存储结构转换为邻接矩阵存储结构,用图G1表示。
MatToList(MGraph *G1,ALGraph *G2)初始条件:图G1存在操作结果:把图的邻接矩阵存储结构转换为邻接表存储结构,用图G2表示。
LocateVex(MGraph *G,VertexType u)初始条件:图G存在,u和G中顶点有相同特征操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1}ADT Graph4程序源代码(包括注释)#include <stdio.h>#include <string.h>#include <malloc.h>#define OK 1#define ERROR 0#define TURE 1#define FALSE 0#define OVERFLOW -1#define INFEASIBLE -2typedef int Status;#define INFINITY 0#define MAX_VERTEX_NUM 20#define MAX_NAME 5typedef char VertexType[MAX_NAME];typedef int VRType;typedef struct ArcCell{VRType adj;/*顶点关系类型。
对无权图,用1(是)或0(否)表示相邻否*//*对带权全图,则为权值类型*/}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedef struct MGraph{VertexType vexs[MAX_VERTEX_NUM];/*顶点向量*/AdjMatrix arcs;/*邻接矩阵*/int vexnum,arcnum;/*图的当前顶点数和弧数*/}MGraph;/* 以下定义邻接表类型 */typedef struct ANode /* 弧的结点结构类型 */{ int end;int begin; /* 该弧的终点位置 */int weight; /* 该弧的相关信息,这里用于存放权值 */ struct ANode *nextarc; /* 指向下一条弧的指针 */}ANode;typedef struct VNode /* 邻接表头结点的类型 */{ VertexType vertex; /* 顶点信息 */int bianhao;ANode *firstarc; /* 指向第一条弧 */}VNode,AdjList[MAX_VERTEX_NUM]; /* AdjList是邻接表类型 */typedef struct ALGraph{ AdjList adjlist; /* 邻接表 */int vexnum,arcnum; /* 图中顶点数n和边数 e */}ALGraph; /* 图的邻接表类型 */int LocateVex(MGraph *G,VertexType u){ /*初始条件:图G存在,u和G中顶点有相同特征*//*操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1*/ int i;for(i=0;i<G->vexnum;++i)if(strcmp(u,G->vexs[i])==0)return i;return -1;}图一/* 建立无向图的邻接表算法 */Status InitALGraph(ALGraph *G){printf("请输入城市的数量及城市间的路径数目\n");scanf("%d%d",&G->vexnum,&G->arcnum);for(i=0;i<G->vexnum;i++){/* 建立顶点表 */printf("请输入第%d个城市的名称\n",i);scanf("%s",&G->adjlist[i].vertex); /* 读入顶点信息 */G->adjlist[i].firstarc=NULL;/* 边表置为空表 */G->adjlist[i].bianhao = i;}printf("每个城市所对应的序号为\n");for(i = 0;i<G->vexnum;i++){printf("序号:%d--->城市:%s\n",G->adjlist[i].bianhao,&G->adjlist[i].vertex); //注意此处的& }return OK;}Status PrintALGraph(ALGraph *G){int i,end,begin,weight;ANode *s;for(i=0;i<G->vexnum;i++){/* 建立顶点表 */printf("%s ------>",&G->adjlist[i].vertex);s = G->adjlist[i].firstarc;while(s!=NULL){printf("( %s,%s ):%d",&G->adjlist[s->end].vertex,&G->adjlist[s->begin].vertex,s->weight);s = s->nextarc;printf("\n");}return OK;}void CreateALGraph(ALGraph *G){int i,j,k,weight;ANode *s;InitALGraph(G);for(k=0;k< G-> arcnum;k++){ /* 建立边表 */printf("\n请输入第%d条边的两个城市的编号及路径的架设费用:",k); scanf("%d",&i);scanf("%d",&j);scanf( "%d",&weight);/* 读入边(vi,vj)的顶点对序号 */s=(ANode*)malloc(sizeof(ANode)); /* 生成边表结点 */if(!s) {printf("申请空间失败!\n");exit(OVERFLOW);}s->begin=j; /* 邻接点序号为j */s->end = i;s->weight = weight;s->nextarc= G->adjlist[i].firstarc;G->adjlist[i].firstarc=s; /*将新结点*s插入顶点vi的边表头部 */s=(ANode*)malloc(sizeof(ANode));if(!s) {printf("申请空间失败!\n");exit(OVERFLOW);}s->begin=i; /* 邻接点序号为i */s->end=j;s->weight=weight;s->nextarc=G->adjlist[j].firstarc;G->adjlist[j].firstarc=s; /* 将新结点*s插入顶点vj的边表头部 */ }PrintALGraph(G);}/* CreateALGraph */Status PrintMGraph(MGraph *G){int a;int i,j;printf("邻接矩阵表示法为:\n");printf("\t");for(i=0;i<G->vexnum;++i)printf("\t%5s ",&G->vexs[i]);printf("\n");for ( i=0; i<G->vexnum; i++){printf("\t%5s ",&G->vexs[i]);for ( j=0; j<G->vexnum; j++){printf("\t%5d ",G->arcs[i][j].adj);}printf("\n");}return OK;}图二Status InitMGraph(MGraph *G){int i,j;printf("请输入城市的数量及城市间的路径数目:\n"); scanf("%d%d",&G->vexnum,&G->arcnum);printf("\n请依次输入城市的名称,字符串类型\n"); for(i=0;i<G->vexnum;++i){/*构造顶点向量*/scanf("%s",&G->vexs[i]);}for(i=0;i<G->vexnum;++i)/*初始化邻接矩阵*/for(j=0;j<G->vexnum;++j)G->arcs[i][j].adj=INFINITY;return OK;}Status CreateMGraph(MGraph *G){/*采用数组(邻接矩阵)表示法,构造无向网G*/int i,j,k,weight,IncInfo;VertexType va,vb;InitMGraph(G);for(k=0;k<G->arcnum;++k){ printf("请输入第%d条路径的起点城市和终点城市的名称及路径的架设费用\n",k); scanf("%s %s %d",&va,&vb,&weight);i=LocateVex(G,va);j=LocateVex(G,vb);G->arcs[i][j].adj=weight;G->arcs[j][i].adj=weight;}PrintMGraph(G);return OK;}typedef struct MINSIZE{//记录从顶点集U到V-U的代价最小的边的辅助数组定义*VertexType adjvex;VRType lowcost;}minside[MAX_VERTEX_NUM];Status mininum(minside closedge,MGraph *G){/*求closedege,lowcost的最小正值*/int i=0,j,k,min;while(!closedge[i].lowcost)i++;min=closedge[i].lowcost;k=i;for(j=i+1;j<G->vexnum;j++)if(closedge[j].lowcost>0)if(min>closedge[j].lowcost){min=closedge[j].lowcost;k=j;}return k;}图三void MiniSpanTree_PRIM(MGraph *G,VertexType u){/*用普利姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边*/ int i,j,k;int qidian,zhongdian,weight;VertexType va,vb;minside closedge;k=LocateVex(G,u);for(j=0;j<G->vexnum;++j)/*辅助数组初始化*/{if(j!=k){strcpy(closedge[j].adjvex,u);closedge[j].lowcost=G->arcs[k][j].adj;}}closedge[k].lowcost=0;printf("最小代价生成树的各条边为:\n");for(i=1;i<G->vexnum;++i){/*选择其余G.vexnum-1个顶点*/k=mininum(closedge,G);/*求出T的下一个结点:第K顶点*/strcpy( va,closedge[k].adjvex);strcpy(vb ,G->vexs[k]);qidian=LocateVex(G,va);zhongdian=LocateVex(G,vb);weight = G->arcs[qidian][zhongdian].adj;printf("weight(%s,%s)=%d\n",va,vb,weight);/*输出生成树的边*/closedge[k].lowcost=0;/*第K顶点并入U集*/for(j=0;j<G->vexnum;++j)if(G->arcs[k][j].adj<closedge[j].lowcost){/*新顶点并入U集后重新选择最小边*/strcpy(closedge[j].adjvex,G->vexs[k]);closedge[j].lowcost=G->arcs[k][j].adj;}}}void InsertSort(ANode *E,int n) //对E[0...n-1]按权值递增有序的进行直接插入排序{int i,j;ANode temp;for(i=1;i<=n;i++){temp=E[i];while(j>=0&&temp.weight<E[j].weight){E[j+1]=E[j];/* 将w大于E[i].w的记录后移 */ j--;}E[j+1]=temp;/* 在j+1处插入E[i] */}}图四void Kriuskal(ALGraph *G){ANode *E;ANode *s;int i,j,end,begin,sn1,sn2,k,n;int vset[MAX_VERTEX_NUM];n = 2*G->vexnum;E=(struct ANode*)malloc(n*sizeof(struct ANode));k=0;for(i=0;i<G->vexnum;i++){/* 将各边存到E[0...n]数组中 */for(j=0;j<G->vexnum;j++)s = G->adjlist[i].firstarc;while(s!=NULL){(E+k)->end = s->end;(E+k)->begin = s->begin;(E+k)->weight = s->weight ;s = s->nextarc;k++;}}InsertSort(E,k); /* 对E数组按w递增排序 */for(i=0;i<G->vexnum;i++)vset[i]=i; /* 初始化辅助数组 */k=1;j=0;while(k<G->vexnum) /* 生成的边数小于n时循环 */{end=(E+j)->end;begin=(E+j)->begin; /* 取一条边的头尾顶点 */sn1=vset[end];sn2=vset[begin];/* 分别得到两个顶点所属的集合编号 */if(sn1!=sn2) /* 两顶点属不同集合,则该边是最小生成树的一条边 */ { printf( "weight(%s %s) : %d\n",&(G->adjlist[end].vertex),&(G->adjlist[begin].vertex),(E+j)->weight);k++; /* 生成边数增 1 */for(i=0;i<n;i++)/* 两个集合统一编号 */if(vset[i]==sn2)vset[i]=sn1;}j++; /* 扫描下一条边 */}图五Status ListToMat(MGraph *G1,ALGraph *G2){int i,j;ANode *s;for(i = 0;i<G2->vexnum;i++){strcpy(G1->vexs[i], G2->adjlist[i].vertex);for(j = 0;j<G2->vexnum;j++){G1->arcs[i][j].adj=INFINITY;}}for(i = 0;i<G2->vexnum;i++){s = G2->adjlist[i].firstarc;while(s){G1->arcs[s->end][s->begin].adj = s->weight; s =s->nextarc;}G1->vexnum = G2->vexnum;G1->arcnum = G2->arcnum;PrintMGraph(G1);return OK;}图六Status MatToList(MGraph *G1,ALGraph *G2) {int i,j;ANode *s,*temp;for(i = 0;i<G1->vexnum;i++){strcpy(G2->adjlist[i].vertex ,G1->vexs[i]);G2->adjlist[i].firstarc = NULL;}for(i = 0;i<G1->vexnum;i++){for(j = 0;j<G1->vexnum;j++){if(G1->arcs[i][j].adj!=INFINITY){s = (struct ANode*)malloc(sizeof(struct ANode)); s->end = i;s->begin = j;s->weight = G1->arcs[i][j].adj;s->nextarc=NULL;if(G2->adjlist[i].firstarc==NULL){G2->adjlist[i].firstarc = s;}else{s->nextarc = G2->adjlist[i].firstarc;G2->adjlist[i].firstarc = s;}}}}G2->vexnum = G1->vexnum;G2->arcnum = G1->arcnum;PrintALGraph(G2);return OK;}Status SelectSaveStructure(){int c;printf("请选择一种算法存储无向图\n");printf("*************************\n");printf("| 1:邻接矩阵 2:邻接表|\n");printf("请按键选择: ");while(1){scanf("%d",&c);if(c==1||c==2) break;else {printf("输入的数字不符合要求,请从新输入\n");}}getchar();return c;}Status SelectSuanFa(){int c;printf("请选择一种算法构建最小生成树\n");printf("*****************************************************\n");printf("| 1:普里姆算法(Prim) 2:克鲁斯卡尔算法(Kruskal)|\n"); printf("*****************************************************\n");printf("请按键选择: ");while(1){scanf("%d",&c);if(c==1||c==2) break;else {printf("输入的数字不符合要求,请从新输入\n");}}getchar();return c;}{ MGraph *G1;ALGraph *G2;int choose;G2=(ALGraph *)malloc(sizeof(ALGraph));choose = SelectSaveStructure();switch(choose){case 1:CreateMGraph(G1);printf("邻接矩阵转换为邻接表mat to list\n"); MatToList(G1,G2);break;case 2:G2=(ALGraph*)malloc(sizeof(ALGraph));if(!G2) exit(OVERFLOW);CreateALGraph(G2);printf("邻接表转换为邻接矩阵list to mat\n"); ListToMat(G1,G2);break;}choose =SelectSuanFa();switch(choose){case 1:printf("采用Prim算法\n");MiniSpanTree_PRIM(G1,G1->vexs[0]);break;case 2:printf("采用Kriuskal算法\n");Kriuskal(G2);break;system("pause");}5程序运行界面程序运行结果在所对应的的函数上方。