n个城市最小生成树实验报告
- 格式:doc
- 大小:89.00 KB
- 文档页数:13
最小生成树(Minimum Spanning Tree)实验报告1. 实验目的本实验旨在通过实践掌握最小生成树算法的基本原理和实现方法。
最小生成树是图论中的一个重要概念,用于解决具有权重的连通图的最优路径问题。
通过本实验,我们将学习如何使用最小生成树算法找到一棵连接图的所有节点且总权重最小的树。
2. 实验原理最小生成树是一个连通图的一种生成树,它的所有边的权重之和最小。
最小生成树的求解算法有多种,其中两种常用的算法是 Prim 算法和 Kruskal 算法。
2.1 Prim 算法Prim 算法是一种贪心算法,从一个节点开始,逐步扩展最小生成树的边。
具体步骤如下: 1. 选择一个起始节点作为最小生成树的根节点。
2. 在当前最小生成树的所有节点中选择一个与该树相连接的权重最小的边,将其加入最小生成树。
3. 将该节点标记为已访问。
4. 重复步骤 2 和步骤 3,直到所有节点都被访问。
2.2 Kruskal 算法Kruskal 算法也是一种贪心算法,通过不断选择权重最小的边来构建最小生成树。
具体步骤如下: 1. 对所有边按照权重进行排序。
2. 依次选择权重最小的边,如果该边的两个端点不在同一个连通分量中,则将该边加入最小生成树,并将这两个端点合并到同一个连通分量中。
3. 重复步骤 2,直到所有节点都在同一个连通分量中,即最小生成树构建完成。
3. 实验步骤本实验将使用 Prim 算法和 Kruskal 算法分别求解给定图的最小生成树。
3.1 数据准备首先,我们需要准备一个具有权重的连通图作为实验数据。
假设该图有 n 个节点和 m 条边,我们可以使用邻接矩阵或邻接表来表示这个图。
3.2 Prim 算法求解最小生成树1.首先,选择一个起始节点作为最小生成树的根节点,并将该节点标记为已访问。
2.初始化一个空的最小生成树,用于存储最终的结果。
3.重复以下步骤,直到所有节点都被访问:1.在当前最小生成树的所有节点中选择一个与该树相连接的权重最小的边,将其加入最小生成树。
最小生成树算法实验报告【实验报告】最小生成树算法实验一、实验目的本次实验旨在研究最小生成树算法,通过对比不同的算法,并对实验结果进行分析,探索最小生成树算法的优劣势和适应场景。
二、实验过程1.算法介绍本次实验中我们将使用两种最小生成树算法:普里姆算法和克鲁斯卡尔算法。
- 普里姆算法(Prim算法):从一个顶点开始,不断在剩下的顶点中选择到当前已有的最小生成树的距离最小的边,将该边的另一个顶点加入树中,直到所有的顶点都加入树中。
- 克鲁斯卡尔算法(Kruskal算法):首先将所有边按照权值从小到大进行排序,然后以最小权值的边开始,依次选择权值最小且不会形成环路的边,直到找到n-1条边为止,其中n为顶点数。
2.实验步骤首先,我们使用Python语言实现了普里姆算法和克鲁斯卡尔算法。
然后,我们构造了一些测试用例,包括不同规模的图和不同权值分布的图。
最后,我们对实验结果进行对比分析。
三、实验结果1.测试用例设计我们设计了三个测试用例,分别为小规模图、中规模图和大规模图,具体如下:-小规模图:顶点数为5的图,权值随机分布。
-中规模图:顶点数为50的图,权值随机分布。
-大规模图:顶点数为100的图,权值随机分布。
2.实验结果分析我们的实验结果如下表所示:算法,小规模图,中规模图,大规模图:-------:,:------:,:------:,:------:普里姆算法,13,455,703从实验结果可以看出,对于小规模图和中规模图,普里姆算法的运行时间明显低于克鲁斯卡尔算法。
但是对于大规模图,克鲁斯卡尔算法的运行时间与普里姆算法的运行时间差距不大,甚至略小于普里姆算法。
这是因为克鲁斯卡尔算法中排序边的时间复杂度为O(ElogE),而普里姆算法中筛选最小距离的边的时间复杂度为O(V^2)。
综上所述,普里姆算法适用于较小规模的图,而克鲁斯卡尔算法适用于较大规模的图。
四、实验总结本次实验研究了最小生成树算法,通过对比实验结果,我们发现不同算法在不同规模的图上的表现有所差异。
数据结构课程设计报告起评分理论成绩实践成绩总成绩院系:专业:班级:学号::教师:时间:目录一、设计要求 (3)1、问题描述 (3)2、功能 (3)3、数据 (3)二、概述与分析 (3)1、图 (3)2、邻接矩阵 (3)3、生成树 (4)4、最小生成树 (5)5、最小生成树的操作 (5)三、程序设计及分析 (6)四、流程图 (7)1、模块结构流程图 (7)2、Prim算法流程设计 (8)五、测试分析 (8)六、总结 (10)七、源程序代码 (10)一、设计要求:1、问题描述构造可以使n个城市连接的最小生成树。
2、功能给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
本人采用的是Prim算法。
3、数据城市间的距离网采用邻接矩阵表示(要求至少6个城市,10条边),邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)二、概述与分析1、图图的定义:图G是有两个集合V和E组成,记做G=(V,E),其中V是定点的有限集合,记做V(G),E是连接V的两个不同的顶点的边的有限集合,记做E(G)。
2、邻接矩阵邻接矩阵是图的一种存储方法,它是表示顶点之间相邻关系的矩阵。
设G=(V,E)是具有n(n>0)个顶点的图,顶点的顺序依次为(v0,v1,…,vn-1),则G的邻接矩阵A是n阶方阵,其定义如下。
1)如果G是无向图,则1 (vi,vj) ∈E(G)A[i][j]=0 其他2)如果G是有向图,则1 <vi,vj> ∈E(G)A[i][j]=0其他3)如果G是带权无向图,则w ij vi≠vj且(vi,vj)∈E(G)A[i][j]= 0 vi =vj∞其他4)如果G是带权有向图,则w ij vi≠vj且<vi,vj> ∈E(G)A[i][j]= 0 vi =vj∞其他邻接矩阵的特点如下:1)图的邻接矩阵表示是唯一的。
实验5 最小生成树算法的设计与实现一、实验目的1、根据算法设计需要, 掌握连通图的灵活表示方法;2、掌握最小生成树算法,如Prim、Kruskal算法;3、基本掌握贪心算法的一般设计方法;4、进一步掌握集合的表示与操作算法的应用。
二、实验内容1、认真阅读算法设计教材和数据结构教材内容, 熟习连通图的不同表示方法和最小生成树算法;2、设计Kruskal算法实验程序。
有n个城市可以用(n-1)条路将它们连通,求最小总路程的和。
设计测试问题,修改并调试程序, 输出最小生成树的各条边, 直至正确为止。
三、Kruskal算法的原理方法边权排序:1 3 14 6 23 6 41 4 52 3 53 4 52 5 61 2 63 5 65 6 61. 初始化时:属于最小生成树的顶点U={}不属于最小生成树的顶点V={1,2,3,4,5,6}2. 根据边权排序,选出还没有连接并且权最小的边(1 3 1),属于最小生成树的顶点U={1,3},不属于最小生成树的顶点V={2,4,5,6}3. 根据边权排序,选出还没有连接并且权最小的边(4 6 2),属于最小生成树的顶点U={{1,3},{4,6}}(还没有合在一起,有两颗子树),不属于最小生成树的顶点V={2,5}4. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,3,4,6}(合在一起),不属于最小生成树的顶点V={2,5}5. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,6},,不属于最小生成树的顶点V={5}6. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,5,6}此时,最小生成树已完成四、实验程序的功能模块功能模块:bool cmp(Edge a,Edge b); //定义比较方法x);//在并查集森林中找到x的祖先int g etfa(intint s ame(int x,int y); //判断祖先是否是同一个,即是否联通 void merge(int x,int y); //合并子树,即联通两子树sort(e+1,e+m+1,cmp); //对边按边权进行升序排序详细代码:#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define M AXN_E 100000#define M AXN_V 100000using namespace std;struct Edge{int f m,to,dist;//边的起始顶点,边的到达顶点,边权}e[MAXN_E];int f a[MAXN_V],n,m; //顶点数组,顶点总数,边总数 //定义比较,只是边权比较bool cmp(Edge a,Edge b){return a.dist < b.dist;}//查找x的祖先是在并查集森林中找到x的祖先x){//getfaint g etfa(intreturn fa[x];if(fa[x]==x)else r eturn fa[x] = getfa(fa[x]);}//判断祖先是否是同一个,即是否联通int s ame(int x,int y){return getfa(x)==getfa(y);}//合并两棵树void merge(int x,int y){int f ax=getfa(x),fay=getfa(y);fa[fax]=fay;}int m ain(){int i;cout<<"请输入顶点数目和边数目:"<<endl;cin>>n>>m;//n为点数,m为边数//输出顶点信息cout<<"各个顶点值依次为:"<<endl;for(i=0;i<n;i++){fa[i]=i;if(i!=0)cout<<fa[i]<<" ";}cout<<endl;cout<<"请输入边的信息(例子:1 4 5 从顶点1到顶点4的边权为5)"<<endl;for(i=1;i<=m;i++)用边集数组存放边,方便排序和调用 cin>>e[i].fm>>e[i].to>>e[i].dist;//sort(e+1,e+m+1,cmp); //对边按边权进行升序排序表示目前的点共存在于多少个集合中,初始情况是每 int r st=n,ans=0;//rst个点都在不同的集合中for(i=1;i<=m && rst>1;i++){int x=e[i].fm,y=e[i].to;函数是查询两个点是否在同一集合中 if(same(x,y))continue;//sameelse{函数用来将两个点合并到同一集合中 merge(x,y);//mergerst--;//每次将两个不同集合中的点合并,都将使rst值减1这条边是最小生成树中的边,将答案加上边权 ans+=e[i].dist;//}}cout<<ans;return 0;}五、测试数据和相应的最小生成树Input:6 101 2 61 3 11 4 52 3 52 5 63 4 53 5 63 6 44 6 25 6 6Putout:18生成树为:七、思考题1、微软面试题一个大院子里住了50户人家,每家都养了一条狗,有一天他们接到通知说院子里有狗生病了,并要求所有主人在发现自己家狗生病的当天就要把狗枪杀掉。
数据结构与算法课程设计报告书题目:n个城市连接的最小生成树班级:1101211学号:1110121137姓名:小张教师:周期:2013年6月4日——6月28 (以下由验收教师填写)成绩:2013 年6月27日提问:使用的什么算法?好处?都实现了哪些功能?在程序的哪里体现的?《n个城市连接的最小生成树》一、课程设计的目的与要求(一)课程设计目的与任务(1)城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本上的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括那些城市间的道路,并显示得到的最小生成树的代价。
(2)表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)(3)最小生成树中包括的边及其权值,并显示得到的最小生成树的代价。
(二)题目要求对所选题目,运用面向过程的分析与设计方法,给出系统分析与设计的结果,要求必须要运用数据结构课程中相关的基本知识;二、设计正文1 系统分析和开发背景按照题目要求需要采用邻接矩阵来存放城市间的距离网,且用Prim算法建立最小生成树并求最小生成树代价。
图的结点信息存放在一个顺序表中,图的边信息存储在一个二维数组edge[MaxVertices][MaxVertices]中,这样就实现了用邻接矩阵存放城市间的距离网。
在Prim算法的函数用两个参数,一个是图G为邻接矩阵存储结构的图;另一个是通过函数得到的最小生成树的结点数据和相应结点的边的权值数据closeVertex.2 功能详细描述输入城市数,显示个城市间的距离,显示最小生成树3、数据结构和数据库设计顺序表定义结构体如下:Typedef struct{DataType list[Maxsize];Int size;}SeqList;其中,DataType为数组(即数据元素)的数据类型,Maxsize表示数组的最大元素个数,list表示顺序表的数组名,size表示顺序表中当前存储的数据元素个数,它必须满足size<= Maxsize,SeqList是该结构体的名称。
课程设计报告问题描述:已知一个无向连通网表示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条边就是需要求出的最小生成树的边。
数据结构实验报告-最小生成树(精选5篇)第一篇:数据结构实验报告-最小生成树电子科技大学实验报告学生姓名:XXX 学号:20***指导教师:刘峤实验地点:信软楼306实验时间:5月17日一、实验室名称:软件实验室二、实验项目名称:数据结构与算法—图三、实验学时:4四、实验原理: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)打印最小生成树边的顶点及权值。
七、实验器材(设备、元器件):八、数据结构及程序#include #include #include typedefstruct {intvex;intgno;}TVex,*TpVex;typedefstruct {intvhead, vtail;intwght;intflag;}TEdge,*TpEdge;typedef struct{TpVex VexList;TpEdge EdgeList;int nvex, nedge;}TGraph, *TpGraph;void begin(TpGraph G){ int i;for(i=1;i<=G->nvex;i++){G->VexList[i-1].gno=i;G->EdgeList[i-1].flag=0;} } int findmin(TpGraph G){ int i,j;int minwght=G->EdgeList[0].wght;for(i=0,j=-1;inedge;i++){ PC机一台,装有C/C++语言集成开发环境。
《程序设计》课程设计姓名:王学号:班级:软件工程00班指导教师:王会青成绩:2010年6月实验一.构造可以使n个城市连接的最小生成树专业:__软件工程___ 班级:__软件姓名:_王___ 学号:_完成日期:_2010/6/26________一、【问题描述】给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
1 城市间的道路网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
2 显示出城市间道路网的邻接矩阵。
3 最小生成树中包括的边及其权值,并显示得到的最小生成树的总代价。
4 输入城市数、道路数→输入城市名→输入道路信息→执行Kruskal 算法→执行 Prim 算法→输出最小生成树二、【问题分析】1.抽象数据类型结构体数组的定义:#ifndef ADJACENCYMATRIXED 程图4.数据类型定义为了用邻接矩阵表示图 G ,先是定义二维数组的每一个元素含道路值然后在图的定义中定义一个此二维数组的结构成员。
并且在图中还定义一个用来存放城市的一维数组及int 型的城市数级道路数。
用二维数组的两个下标表示道路,这两个下标又在一位数组中对应两个城市。
这样就建立起了一个城市到城市之间的道路网。
4. 程序主要模块说明:该程序共含5个模块,本人负责其中2个模块构造:***************LocateVex(MGraph G, VertexType v)****************Status LocateVex(MGraph G, VertexType v);{while (strcmp[i], v)) {i++;}返回 i;}**************** CreateUDN************************* {输入城市数、道路数;for (i=0; i<城市数; ++i) 输入城市名;for (i=0; i<城市数; ++i)for(j=0; j<城市数; ++j)初始化邻接矩阵:道路值= INFINITY;for (i=0; i<城市数; ++i)for(j=0; j<城市数; ++j)输入两个城市表示道路,输入道路值;}PRIM算法************************** MiniSpanTree_PRIM********* void MiniSpanTree_PRIM(MGraph G, VertexType u){定义辅助数组:closedge closeEdge;初始化:strcpy(closeEdge[j].adjvex, u);closeEdge[j].lowcost = [k][j].adj;for (i=1; i<; ++i){在其余个城市中找到离辅助数组中标记的道路最小值;显示找到的道路;标记新找到的城市;}}********************** Minimum*****************Status Minimum(closedge closeEdge, int n){在辅助数组中找到道路值最小的道路的两点城市:if ((closeEdge[i].lowcost != 0) && (minTemp > closeEdge[i].lowcost))返回该城市在 G 中的位置}三、【功能实现】#include <>#include <>#include <>#include <>#include ""#include ""#include ""#include ""#include ""#include ""#include ""MGraph G; = UDN;int i, j, k;VertexType v1, v2;VRType w;printf(" 构造可以使N个城市连接的最小生成树\n");printf("请输入城市数、道路数(至少6个城市,10条道路):");cin>>>>;for (i=0; i<; ++i) dj = INFINITY;nfo = NULL;}}printf("请输入一条道路连接的两个城市名及权值:\n");for (k=0; k<; ++k) dj = w; owcost != 0) && (minTemp > closeEdge[i].lowcost)){minTemp = closeEdge[i].lowcost;flag = i;}}return flag;}void MiniSpanTree_PRIM(MGraph G, VertexType u){djvex, u);closeEdge[j].lowcost = [k][j].adj;}}cout<<"\n\n+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\\n";cout<<"|用Prim算法求最小生成树的各条边依次为:\n-----";closeEdge[k].lowcost = 0; owcost = MIN{closeEdge[vi].lowcost | closeEdge[vi].lowcost > 0, vi∈V-U}cout<<'<'<<closeEdge[k].adjvex<<','<<[k]<<'>'; owcost;closeEdge[k].lowcost = 0; dj < closeEdge[j].lowcost) djvex, [k]);closeEdge[j].lowcost = [k][j].adj;}}}cout<<"\n|总代价:"<<totalCost<<endl;cout<<"+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^/\n";}问题描述】某次科研调查时得到了n个自然数,每个数均不超过00(*109)。
数据结构课程设计报告题目:最小生成树问题院(系):计算机工程学院学生姓名:班级:学号:起迄日期:指导教师:2011—2012年度第 2 学期一、需求分析1.问题描述:在n个城市之间建设网络,只需保证连通即可,求最经济的架设方法。
存储结构采用多种。
求解算法多种。
2.基本功能在n个城市之间建设网络,只需要架设n-1条线路,建立最小生成树即可实现最经济的架设方法。
程序可利用克鲁斯卡尔算法或prim算法生成最小生成树。
3.输入输出以文本形式输出最小生成树,同时输出它们的权值。
通过人机对话方式即用户通过自行选择命令来输入数据和生成相应的数据结果。
二、概要设计1.设计思路:因为是最小生成树问题,所以采用了课本上介绍过的克鲁斯卡尔算法和 prim算法两种方法来生成最小生成树。
根据要求,需采用多种存储结构,所以我选择采用了邻接表和邻接矩阵两种存储结构。
2.数据结构设计:图状结构:ADT Graph{数据对象V:V是具有相同特性的数据元素的集合,称为顶点集。
数据关系R:R={VR}VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧,谓词P(v,w)定义了弧<v,w>的意义或信息}基本操作:CreateGraph( &G, V, VR )初始条件:V是图的顶点集,VR是图中弧的集合。
操作结果:按V和VR的定义构造图G。
DestroyGraph( &G )初始条件:图G存在。
操作结果:销毁图G。
LocateVex( G, u )初始条件:图G存在,u和G中顶点有相同特征。
操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回其它信息。
GetVex( G, v )初始条件:图G存在,v是G中某个顶点。
操作结果:返回v的值。
PutVex( &G, v, value )初始条件:图G存在,v是G中某个顶点。
操作结果:对v赋值value。
数据结构实验最小生成树数据结构实验报告最小生成树问题一、问题描述:若要在n个城市之间建设通信网络,只需要架设n-1条线路即可。
如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题基本要求(1)从文件中读入图的信息。
(2)利用克鲁斯卡尔算法求网的最小生成树。
(3)以文本形式生成树中各条边以及他们的权值。
二(需求分析:1、需定义结构体数组,根据权值逐一选择边。
三(概要设计抽象数据类型:需定义结构体数组,存储每条边的起点,终点,权值。
算法的基本思想:1、图的信息的读取:定义结构体数组,存储每条边的起点,终点,权值。
2、对每条边在数组中的位置处理:选边需从最小的开始,故按边的权值从小到大进行排序。
3、边的选取: 从最小的边的开始,若边的两端点不属于同一集合,则选取该边。
并将该边的两个顶点所在的两个集合合并成为一个。
因为有n个顶点,故只需选取n-1条边。
程序的流程:(1) 输入模块: 读入图的信息(顶点和边,用结构体数组进行存储)。
(2) 处理模块:Kruskal算法。
(3) 输出模块:将结果输出。
四(详细设计:算法的具体步骤: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;}五(调试分析:将选边的过程输出来检验算法的正确性。
数据结构实验报告名称:最小生成树班级:122姓名:*****学号:***********指导老师:********一、设计目的与任务1。
1课程设计目的本课程设计的目的是了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;提高综合运用所学的理论知识和方法独立分析和解决问题的能力;训练用系统的观点和软件开发一般规范进行软件开发。
1。
2课程设计的任务问题描述:已知一个无向连通网表示n个城市以及城市间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边上的权值表示相应的代价.对于n个点的连通网能建立许多不同的生成树,每一棵生成树都可以是一个通信网。
我们要选择一棵生成树,使总的耗费最小。
二、设计方案2。
1需求分析(1)建立一个图,其存储方式可以采用邻接矩阵形式或者邻接表;(2)利用普利姆算法或者克鲁斯卡尔算法求出网的最小生成树;(3)输入各城市的数目以及各个城市之间的距离。
将城市之间的距离当做网中各点之间的权值。
按顺序输出生成树中各条边以及它们的权值。
2.2数据结构分析构造最小生成树的方法:最初生成树为空,即没有一个结点和一条边,首先选择一个顶点作为生成树的根,然后每次从不在生成树中的边中选择一条权值尽可能小的边,为了保证加入到生成树中的边不会造成回路,与该边邻接的两个顶点必须一个已经在生成树中,一个则不在生成树中,若网中有n个顶点(这里考虑的网是一个连通无向图),则按这种条件选择n—1边就可以得到这个网的最小生成树了。
详细的过程可以描述为:设置2个集合,U集合中的元素是在生成树中的结点,V—U集合中的元素是不在生成树中的顶点。
首先选择一个作为生成树根结点的顶点,并将它放入U集合,然后在那些一端顶点在U集合中,而另一端顶点在V-U集合中的边中找一条权最小的边,并把这条边和那个不在U集合中的顶点加入到生成树中,即输出这条边,然后将其顶点添加到U集合中,重复这个操作n-1次。
C语言与数据结构实习报告题目:构造可以使n个城市连接的最小生成树学号姓名专业班级指导教师实践日期目录一、综合训练目的与要求 (3)二、综合训练任务 (3)三、总体设计 (3)四、详细设计说明 (4)五、调试与测试 (6)六、实习日志 (8)七、实习总结 (9)八、附录:核心代码清单 (10)一、综合训练目的与要求按照数据结构、C程序设计教学计划的安排,7月19日到30日,开展为期两周的数据结构与C程序设计课程设计。
该课程设计是数据结构、C语言程序设计课程的重要实践教学环节,是一次全面的系统分析与设计能力的培养,是实现该专业学生总体培养目标的重要教学环节。
使学生通过了解学科领域的发展动向,培养数据结构与程序设计的基本思想,独立分析和解决实践问题的能力,提高和锻炼学生动手能力。
实习的基本要求(1)结合实践,学生选题与教师指定题目相结合,老师对题目的合理性、学生分组进行确认;(2)对所选题目,运用面向过程的分析与设计方法,给出系统分析与设计的结果,要求必须要运用数据结构课程中相关的基本知识;(3)选择熟悉的开发工具,用C语言完成系统实现和测试,掌握系统实现和测试的方法,必须要有详尽的程序注释;(4)撰写开发文档,培养编写系统分析与设计文档的水平。
二、综合训练任务主要任务:给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
设计该程序的基本要求:1、城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
2、表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)3、最小生成树中包括的边及其权值,并显示得到的最小生成树的代价。
三、总体设计《1》该程序的主要功能:能实现根据输入城市的信息可以判断该城市间的距离网是否构成最小生成树,遍历城市生成最小生成树,通过计算得到最小生成树的代价。
最小生成树实验报告最小生成树(Minimum Spanning Tree,MST)是图论中的一个重要概念,用于在一个连通带权无向图中找到一个子图,使得这个子图是一个树(即无环连通图),并且所有边的权值之和最小。
最小生成树在诸多领域有着广泛的应用,如网络设计、电力传输等。
在本次实验中,我们实现了最小生成树算法,并将其运用到多个实际问题上。
下面将依次介绍算法原理、实现过程、实验结果以及对实验的进一步改进。
1.算法原理Kruskal算法的基本思想是,首先将所有边按照权值从小到大排序,然后从最小的边开始,逐一加入生成树,直到生成树包含了所有的顶点。
在加入一条边时,需要判断这条边将两个顶点连通起来是否会形成环,如果不会则加入生成树。
Prim算法的基本思想是,从一个顶点开始,逐步加入生成树的顶点,每次加入一个顶点时,选择一个离生成树最近的点,并将这个点加入生成树。
通过不断的选择顶点和加入边,最终得到最小生成树。
2.实现过程首先,我们实现了图的数据结构和边的数据结构。
在图的数据结构中,我们定义了图的顶点数和边数,并用邻接矩阵来表示图的连接情况。
边的数据结构包含了两个顶点和边的权值。
其次,我们实现了两种算法。
对于Kruskal算法,我们首先将所有边按照权值从小到大进行排序。
然后,逐个加入边,判断是否形成环。
如果不会形成环,则将该边加入生成树。
最后,我们使用并查集数据结构来判断两个顶点是否连通。
对于Prim算法,我们首先选择一个起点作为生成树的初始顶点,并将其加入生成树。
然后,每次选择一个离生成树最近的顶点,并将其加入生成树,同时更新其他顶点到生成树的距离。
最后,所有顶点都被加入生成树后,得到最小生成树。
3.实验结果我们在实验中选择了不同大小的图进行测试。
经过对比,我们发现Kruskal算法和Prim算法得到的最小生成树结果是一致的,但是Kruskal 算法的时间复杂度要稍高于Prim算法。
具体的结果如下:对于一个边数为10的图,我们得到了如下最小生成树:1-2-4-5-3总权重为12对于一个边数为20的图,我们得到了如下最小生成树:2-1-4-5-3总权重为16对于一个边数为30的图2-1-4-5-6-7-3总权重为22从实验结果来看,无论是规模较小的图还是规模较大的图,我们都能够得到最小生成树,并且所得到的结果是正确的。
最小生成树(实验报告)1.功能要求:1.在n各城市间建设通讯网络,用最小成本架设线路。
2.要求建立N个城市间通信网络;3.增加删除城市节点;求最小生成树,输出各节点及边上的权值。
2.数据要求:1.原始数据:城市的代码,为int类型数值,由而且仅有0开始递增,范围0—99;两城市间的架线的成本,为unsigned类型数值,范围为0—9999 。
2.输入的形式为(vi,vj,weight),vi,vj分别为两城市的代码。
weight为城市vi与城市vj之间架线的成本。
3.建立存储边的链表,存储结点记录信息为边的权值和该边所连接的城市代码。
4.建立存储所有信息的图。
3.数据处理:1.追加城市:输入数据后,可以追加数据,在原基础上加入新的数据。
2.删除城市:分为按边删除和按城市结点删除。
按边删除:输入一条边及连接的城市的代码,在链表中找出匹配的结点删除。
按城市结点删除:输入一个城市代码,在链表中找到与该点有关的边删除。
3.输出邻接矩阵:对输入的数据建立图,以邻接矩阵的形式显示出来,没有连接的城市间权值设置为10000,连接的城市间权值设为边的权值。
4.选出最优架线线路:利用kruskal方法在图中选择最小生成树,既城市间的最优架线线路,输出格式为(vi,vj,weight),vi,vj为所需连接的两城市代码,weight为这两个城市间架线的成本。
二、概要设计系统设计图:数据存储结构(变量均为全局变量):int n; //记录城市点数量int m; //记录城市边的数量typedef struct LNode //定义一个链表结点,四个属性{unsigned weight; //边的权值int vi,vj; //边的两个端点的城市代码struct LNode *next; //指针的下一个结点};int cs[100][100]; //存储由链表中数据生成的图int ChengShi[100]; //在kruskal方法中记录已经连接到的城市LNode *LX= new LNode; //存储边的链表的头指针LNode *P; //存储边的链表的为指针该系统三个子系统:数据增加和数据输入:void shuju_shuru()功能:1.确定城市数目n和边数目m。
作业1最小生成树的生成算法1.1算法应用背景在实际生活中, 图的最小花费生成树问题有着广泛的应用。
例如, 用图的顶点代表城市, 顶点与顶点之间的边代表城市之间的道路或通信线路, 用边的权代表道路的长度或通信线路的费用, 则最小花费生成树问题, 就表示为城市之间最短的道路或费用最小的通信线路问题。
其中普里姆算法是使用贪婪法策略设计的典型算法。
1.2算法原理在一给定的无向图G = (V, E) 中, (u, v) 代表连接顶点u 与顶点v 的边(即), 而w(u, v) 代表此边的权重, 若存在T 为E 的子集(即)且为无循环图, 使得的w(T) 最小, 则此T 为G 的最小生成树。
许多应用问题都是一个求无向连通图的最小生成树问题。
例如:要在n个城市之间铺设光缆, 主要目标是要使这n 个城市的任意两个之间都可以通信, 但铺设光缆的费用很高, 且各个城市之间铺设光缆的费用不同;另一个目标是要使铺设光缆的总费用最低。
这就需要找到带权的最小生成树。
1.3算法描述1)最小生成树之普里姆算法描述:令G=(V,E,W), 为简单期间, 令顶点集为V={0,1,2…, n-1}。
假定与顶点i, j相关联的边为ei, j, ei, j的权用c[i][j]表示, T是最小花费生成树的边集。
这个算法维护两个顶点集合S 和N, 开始时: 令T=Ф,S={0},N=V-S。
然后, 进行贪婪选择, 选取i∈S, j∈N, 并且c[i][j]最小的i和j;并使S=S∪S{j},N=N-{j},T=T∪{ei, j}.重复上述步骤, 直到N为空, 或找到n-1条边为止。
此时, T中的边集, 就是所要求取的G中的最小花费生成树。
由此, 可描述普里姆算法的步骤如下:(1)T=Ф, S={0},N=V-S。
(2)如果N为空, 算法结束;否则, 转步骤(3)。
(3)寻找使i∈S, j∈N, 并且c[i][j]最小的i和j。
(4)S=S∪S{j},N=N-{j},T=T∪{ei, j};转步骤(2)。
《数据结构》课程设计报告构造可以使n个城市连接的最小生成树学校:平顶山学院设计题目(问题)描述和要求给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
二、系统分析与概要设计根据问题描述和要求,系统要求能够显示最小生成树的边,权值和得到的最小生成树的代价。
确定程序的数据结构(抽象数据类型)及“邻接矩阵的数据类型”、“临时数组的存放的数据类型”、邻接矩阵的创建等各模块定义。
做此设计,城市间的道路网用邻接矩阵来表示。
若两个城市之间不存在道路,则将相应的权值设置为自己定义的无穷大值。
此程序的目的是:显示最小生成树的边,权值和得到的最小生成树的代价。
因此该程序的指令是:输入城市数和道路数—>输入城市名—>输入道路信息—>执行prim算法—>输出最小生成树。
三、详细设计和编码1、邻接矩阵的数据类型的定义如下:typedef struct{ int no; /*顶点编号*/string name; /*顶点其他信息*/ } VertexType; /*顶点类型*/typedef struct{ int edges[MAXV][MAXV]; /*邻接矩阵*/int vexnum,arcnum; /*顶点数,弧数*/VertexType vexs[MAXV]; /*存放顶点信息*/ }MGraph;2、临时数组的存放的数据类型struct {int closest; // U集中的顶点序号int lowcost; // 边的权值} closedge[MAXV];int const INF=32767; /*INF表示∞*/3、prime算法实现:(原理见实验说明)void prime(MGraph g,int v){int lowcost[MAXV];int min;int closest[MAXV];int i,j,k;for(i=0;i<g.vexnum;i++){lowcost[i]=g.edges[v][i];closest[i]=v;}for(i=1;i<g.vexnum;i++){min=INF;for(j=0;j<g.vexnum;j++)if(lowcost[j]!=0&&lowcost[j]<min){min=lowcost[j];k=j;}printf("边(%d,%d)权为:%d\n",closest[k],k,min);lowcost[k]=0;for(j=0;j<g.vexnum;j++)if(g.edges[k][j]!=0&&g.edges[k][j]<lowcost[j]){lowcost[j]=g.edges[k][j];closest[j]=k;}}}4、邻接矩阵的创建void CreatMGraph(MGraph &M){int n,e;cout<<"输入定点数:";cin>>n;M.vexnum=n;cout<<"输入弧数:";cin>>e;M.arcnum=e;for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i==j)M.edges[i][j]=0;elseM.edges[i][j]=INF;}}cout<<"输入边的权:(如1 2 3 表示点到点的权时)"<<endl;for(int i=0;i<2*e;i++){int x,y,z;cin>>x>>y>>z;M.edges[x][y]=z;}cout<<"输入点编号,名字:"<<endl;for(int i=0;i<n;i++){int No;string str;cin>>No>>str;M.vexs[i].name=str;M.vexs[i].no=No;}}int const MAXV=16。
数据结构课程设计报告题目:最小生成树问题院系:信息学院班级:信管11-2姓名:王裕辰学号:1101051024指导教师:张晓庆实习报告:最小生成树问题题目:最小生成树问题班级:信管11-2 姓名:王裕辰学号:1101051024 完成日期:2013-6-20一、需求分析1. 要在n个城市间建设通信网络,只需要架设n-1条线路即可,建立的最小生成树即能实现付出最低的经济代价。
2. 程序利用的是克鲁斯卡尔算法求网的最小生成树。
3.输出结果为文本形式的生成树和他们之间的权值。
4. 演示程序在按照提示相应输入数据之后,计算结果显示出来。
5. 数据测试《a,b》4 《a,c》3 《b,c》5 《b,e》9 《b,d》5《c,d》5 《c,h》5 《d,e》7 《d,f》6 《d,g》5《d,h》4 《e,f》3 《f,g》2 《g,h》6二、概要设计为实现上述功能,需要图这个抽象数据类型。
图抽象数据类型定义ADT Graph{数据对象:D={ai|ai∈Elemset,i=1,2,3,…n,n>=0}数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2, … n}基本操作:CreatGraph(&G,v,vr)初始条件:v是图的顶点集,vr是图中弧的集合。
操作结果:按v和vr的定义构建图。
DestroyGRaphael(&G)初始条件:图G存在。
操作结果:销毁图G。
GetVex(G,v)初始条件:图G存在,v是G中某个顶点。
操作结果:返回v的值。
PutVex(&G,v,value)初始条件:图G存在,v是G中某个顶点。
操作结果:对v赋值value。
InsertVex(&G,v)初始条件:图G存在,v和图中某个顶点有相同特点。
操作结果:在图G中增添新顶点v。
}ADT Graph本程序包含以下模块:(1)主程序模块;其中又包括输入建立图和执行克鲁斯卡尔算法两个过程void main(){初始化;输入数据;执行功能;输出结果;}(2)图模块:实现图的抽象数据类型(3)元素结构单元模块:定义图的每个元素的结构各模块之间的调用关系如下:主程序图模块元素结构单元模块三、详细设计1、边类型,邻接矩阵和图类型:typedefstruct //定义边结构体{int begin; //开始点int end;int weight;}edge;typedefstruct //邻接矩阵{intadj; //权值类型int weight;}AdjMatrix[MAX][MAX];typedefstruct//定义图类型{AdjMatrix arc; //邻接矩阵intvexnum, arcnum; //顶点数弧数}MGraph;2、主程序及函数的分析void main(){ //主程序int c;printf("最小生成树问题\n");MGraph *G;G=(MGraph*)malloc(sizeof(MGraph));if(!G) exit(OVERFLOW);CreatGraph(G);//创建图并输入图的相关信息MiniSpanTree(G); //利用克鲁斯卡尔算法计算最小生成树并输出结果}Status CreatGraph(MGraph *G){//采用邻接矩阵表示法,构造图Gint i, j;charn, m,te;printf("请输入边数和顶点数:\n");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("请输入有边的2个顶点\n");scanf("%d %d",&n,&m);if(n>m){te=n;n=m;m=te;}while(n<0||n>G->vexnum||m<0||m>G->vexnum||m==n){printf("输入错误! 请重新输入:\n");scanf("%d%d",&n,&m);}G->arc[n][m].adj=G->arc[m][n].adj=1;getchar();printf("请输入%d与%d之间的权值: ", n, m);scanf("%d",&G->arc[n][m].weight);}printf("\n邻接矩阵为:\n");for ( i=1; i<=G->vexnum; i++){for ( j=1; j<=G->vexnum; j++){printf("%d ",G->arc[i][j].adj);}printf("\n");}return OK;}Status Swapn(edge *edges,int i, int j){//交换权值以及边的头和尾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;return OK;}Status 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权排序之后的为:\n");for (i=1; i<=G->arcnum; i++)//将排序后的边的权值进行输出{printf("<< %d, %d >> %d\n", edges[i].begin, edges[i].end, edges[i].weight);}return OK;}int Find(int *parent, int f){ // 找尾参数为 parent【f】while ( parent[f] > 0){f=parent[f];}return f;}Status 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; //如果为1进行赋值k++;}}}Sort(edges, G); //对图G每条边的权值进行排序for (i=1; i<=G->arcnum; i++){parent[i]=0;}printf("\n最小生成树为:\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); //将边的头、尾和权值进行输出}}return OK;}四、调试结果及说明运行程序后出现下图所示界面输入边数和定点数分别为:14和8按提示分别输入以下数据:《1,2》4 《1,3》3 《2,3》5 《2,5》9 《2,4》5 《3,4》5 《3,7》5 《4,5》7 《4,6》6 《4,7》5 《4,8》4 《5,6》3 《6,7》2 《7,8》6最终得到如下结果:。
数据结构课程设计报告起评分理论成绩实践成绩总成绩院系:专业:班级:学号:姓名:教师:时间:目录一、设计要求 (3)1、问题描述 (3)2、功能 (3)3、数据 (3)二、概述与分析 (3)1、图 (3)2、邻接矩阵 (3)3、生成树 (4)4、最小生成树 (5)5、最小生成树的操作 (5)三、程序设计及分析 (6)四、流程图 (7)1、模块结构流程图 (7)2、Prim算法流程设计 (8)五、测试分析 (8)六、总结 (10)七、源程序代码 (10)一、设计要求:1、问题描述构造可以使n个城市连接的最小生成树。
2、功能给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
本人采用的是Prim算法。
3、数据城市间的距离网采用邻接矩阵表示(要求至少6个城市,10条边),邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)二、概述与分析1、图图的定义:图G是有两个集合V和E组成,记做G=(V,E),其中V是定点的有限集合,记做V(G),E是连接V的两个不同的顶点的边的有限集合,记做E(G)。
2、邻接矩阵邻接矩阵是图的一种存储方法,它是表示顶点之间相邻关系的矩阵。
设G=(V,E)是具有n(n>0)个顶点的图,顶点的顺序依次为(v0,v1,…,vn-1),则G的邻接矩阵A是n阶方阵,其定义如下。
1)如果G是无向图,则1 (vi,vj) ∈E(G)A[i][j]=0 其他2)如果G是有向图,则1 <vi,vj> ∈E(G)A[i][j]=0其他3)如果G是带权无向图,则w ij vi≠vj且(vi,vj)∈E(G)A[i][j]= 0 vi =vj∞其他4)如果G是带权有向图,则w ij vi≠vj且<vi,vj> ∈E(G)A[i][j]= 0 vi =vj∞其他邻接矩阵的特点如下:1)图的邻接矩阵表示是唯一的。
数据结构课程设计报告起评分理论成绩实践成绩总成绩院系:专业:班级:学号:姓名:教师:时间:目录一、设计要求 (3)1、问题描述 (3)2、功能 (3)3、数据 (3)二、概述与分析 (3)1、图 (3)2、邻接矩阵 (3)3、生成树 (4)4、最小生成树 (5)5、最小生成树的操作 (5)三、程序设计及分析 (6)四、流程图 (7)1、模块结构流程图 (7)2、Prim算法流程设计 (8)五、测试分析 (8)六、总结 (10)七、源程序代码 (10)一、设计要求:1、问题描述构造可以使n个城市连接的最小生成树。
2、功能给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
本人采用的是Prim算法。
3、数据城市间的距离网采用邻接矩阵表示(要求至少6个城市,10条边),邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)二、概述与分析1、图图的定义:图G是有两个集合V和E组成,记做G=(V,E),其中V是定点的有限集合,记做V(G),E是连接V的两个不同的顶点的边的有限集合,记做E(G)。
2、邻接矩阵邻接矩阵是图的一种存储方法,它是表示顶点之间相邻关系的矩阵。
设G=(V,E)是具有n(n>0)个顶点的图,顶点的顺序依次为(v0,v1,…,vn-1),则G的邻接矩阵A是n阶方阵,其定义如下。
1)如果G是无向图,则1 (vi,vj) ∈E(G)A[i][j]=0 其他2)如果G是有向图,则1 <vi,vj> ∈E(G)A[i][j]=0其他3)如果G是带权无向图,则w ij vi≠vj且(vi,vj)∈E(G)A[i][j]= 0 vi =vj∞其他4)如果G是带权有向图,则w ij vi≠vj且<vi,vj> ∈E(G)A[i][j]= 0 vi =vj∞其他邻接矩阵的特点如下:1)图的邻接矩阵表示是唯一的。
2)无向图的邻接矩阵一定是一个对称矩阵。
因此,按照压缩存储的思想,在具体存放邻接矩阵是只需要存放上(或下)三角形阵的元素即可。
3)不带权的有向图的邻接矩阵一般是稀疏矩阵,因此,当图的顶点较多时,可以采用三元组表的方法存储邻接矩阵。
4)对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点Vi的度。
5)对于有向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点vi的出度(或入度)。
6)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连。
但是,要确定图中有多少条边,则必须按行和按列对每个元素进行检测,所花费的时间大家很大,这是用邻接矩阵存储图的局限性。
3、生成树一个连通图的生成树是一个极小连通图,它含有图中全部顶点,但只有构成一颗树的(n-1)条边。
如果在一颗生成树上添加一条边,必定构成一个环:因为这条边使得它依附的那两个顶点之间有了第2条路径。
一颗有n个顶点的生成树(连通无回路图)有且仅有(n-1)条边,则一定有回路。
但是,有(n-1)条边的图不一定都是生成树。
生成树的特点:1、连通且无环;2、包含原图中的全部n个顶点,但只有n-1条边;3、是原图的极小连通子图;4、最小生成树对于一个带权(假定每条边上的权值均大于零的实数)连通无向图G中的不同生成树,其每棵树的所有边上的权值之和也可能不同;图的所有生成树中的具有边上的权值之和最小的树成为图的最小生成树。
最小生成树的典型用途:欲在n个城市间建立通信网. n个城市可能有n(n-1)/2条线路,但铺n-1条线路即可连通;因为每条线路都会有对应的经济成本,那么,如何选择n–1条线路,使总费用最少?构造数学模型:顶点———表示城市,有n个;边————表示线路,有n–1条;边的权值—表示线路的经济代价;连通网——表示n个城市间通信网。
5、最小生成树的操作1、Prim算法:假设G=(V,E)是连通图,T=(U,TE)为欲构造的最小生成树,初始化U={u0},TE为空,重复以下操作:在所有u∈U,v∈V-U的边(u,v)∈E中,选择一条权最小的边(u,v)并入TE,同时将v并入U,直到U=V为止,此时T=(U,TE)是G的一棵最小生成树。
2、在prim算法中需要解决的两个问题:1)在无向网中,当出现从一个顶点到其它顶点时,若其边上的权值相等,则可能从某一起点出发时会得出不同的最小生成树,但最小生成树的权必定都相等,此时我们应该怎样将所有的最小生成树求解出来;2)每次如何从生成树T中到T外的所有边中,找出一条最短边。
例如,在第k次(1≤k≤n-1)前,生成树T中已有k个顶点和k-1条边,此时T中到T外的所有边数为k(n-k),当然它也包括两顶点间没有直接边相联,其权值被看做常量INF的边在内,从如此多的边中查找最短边,其时间复杂度为O(k(n-k)),显然是很费时的,是否有一种好的方法能够降低查找最短边的时间复杂度。
三、程序设计及分析定义结构体和常量#define MAXV 30#define INF 32767 //INF 表示无穷大struct Node{int weight;int vex;//存放顶点编号int lowcost;//存放顶点权值};struct MGraph{int vexs[MAXV],n,e; //vexs表示顶点向量;n,e分别表示图的顶点数和边数Node city[MAXV][MAXV]; //邻接矩阵};Node closest[MAXV];// 存放每个顶点所连接的边所对应的权值1. 函数功能int Locate(MGraph &g,int V) //求顶点位置函数MGraph CreateMap(MGraph &g) //创建图在其函数体中,首先通过键盘输入网中顶点数,若顶点个数<=1时,显示“最小生成树不存在”,然后返回主调函数;否则,继续通过键盘输入网中的边数,通过二重for循环初始化邻接矩阵,然后输入各个顶点的编号及每条边的权值。
int Min(MGraph &g,Node closest[])//closest[]中权值最小的边void prim(MGraph &g,int u)// 从顶点u出发,按普里姆算法构造连通图g的最小生成树,并输出生成树的每条边定义一个p用于存放最小生成树中的顶点(按生成最小生成树时的顺序存放),调用函数Locate()求出起点u在顶点向量表中的位置,将u存放到p的顶点向量表中,初始化初始化U={u},利用for循环对V-U中的顶点i,初始化closest[i],再利用for循环找n-1条边(n=g.n),其中,调用函数Min()求出辅助数组closest[]中权值最小的边, 并将其在辅助数组中的相应位置返回到主调函数中并赋给k0,此时closest[k0]中存有当前最小边(u0, v0)的信息,将边所对应的终点放入p的顶点向量表中,累加边的权值;然后,输出;最后,在顶点v0并入U之后,利用for循环更新closest[i];当所有的顶点v0都纳入U 集合之后,输出最小生成树的权值之和。
2、Prim算法流程设计如图六个城市之间共有10条路,运用Prim算法:选定第一个点①,从它closest的边中选择最短边①---②,权值为1;从①②的closest的边中选择最短边①---⑥,权值为2;从①②⑥的closest的边中选择最短边⑥---③,权值为3;从①②⑥③的closest的边中选择最短边③---④,权值为2;从①②⑥③④的closest的边中选择最短边④---⑤,权值为4所得最小生成树的权值为1+2+3+2+4=12.① 1 ②① 1 ②2 8 ⑤10 6 7 2 45 4 3 ⑥③ 2 ④③ 2 ④五、测试分析系统运行后出现的界面:根据流程图模型输入相应的数字进行调试检验:六、总结这个课程设计参考了《数据结构(C语言版)》(清华大学出版社),在运行过程中由于prim函数中没有定义p来存放最小生成树中的顶点,导致结果部分会有问题,经过改进后就避免了此类问题。
七、源程序代码#include<iostream.h>#include<stdio.h>#include<string.h>#include<malloc.h>const int MAXV=30; //最多顶点个数const int INF=32768;//表示极大值,即∞struct Node{int weight;int vex;//存放顶点编号int lowcost;//存放顶点权值};struct MGraph{int vexs[MAXV],n,e; //vexs表示顶点向量;n,e分别表示图的顶点数和边数Node city[MAXV][MAXV]; //邻接矩阵};Node closest[MAXV];//求最小生成树时的辅助数组int Locate(MGraph &g,int V) //求顶点位置函数{int j=-1,k;for(k=0;k<g.n;k++)if(g.vexs[k]==V){j=k;break;}return j;}MGraph CreateMap(MGraph &g) //创建图{int i,j,k,v1,v2,vex,m=1;cout<<"请输入城市的个数:";cin>>g.n;if(g.n<=1){cout<<"最小生成树不存在!"<<endl;return g;}else{cout<<"请输入城市的边数:";cin>>g.e;for(i=0;i<g.n;i++) //初始化邻接矩阵for(j=0;j<g.n;j++)if(i==j)g.city[i][j].weight=0;elseg.city[i][j].weight=INF;cout<<"请输入城市的顶点编号:"; //输入图中的顶点编号for(i=0;i<g.n;i++)cin>>g.vexs[i];cout<<"输入每条边所对应的两个顶点及权值<格式:起点城市终点城市权值>!"<<endl;for(k=0;k<g.e;k++){cout<<"请输入第"<<m++<<"条边:";cin>>v1>>v2>>vex; //输入一条边的两个顶点及权值i=Locate(g,v1);j=Locate(g,v2);g.city[i][j].weight=vex;g.city[j][i].weight=vex;}return(g);}}int Min(MGraph &g,Node closest[])//closest[]中权值最小的边{int i,min,j;min=INF;for(i=0;i<g.n;i++)if(closest[i].lowcost<min&&closest[i].lowcost!=0){min=closest[i].lowcost;j=i;}return j;//返回权值最小的边在辅助数组中的位置}void prim(MGraph &g,int u)//从顶点u出发,按普里姆算法构造连通图g的最小生成树,并输出生成树的每条边{MGraph p;int i,j,k,k0,u0,v0,s=0,n=0;k=Locate(g,u);//k为顶点u的位置p.vexs[n++]=u;closest[k].lowcost=0;//初始化U={u}for(i=0;i<g.n;i++)if(i!=k) //初始化closest[i]{closest[i].vex=u;closest[i].lowcost=g.city[k][i].weight;}for(j=1;j<=g.n-1;j++)//选择其余的n-1条边(n=g.n){k0=Min(g,closest);//closest[k0]中存有当前最小边(u0, v0)的信息u0=closest[k0].vex;//u0∈Uv0=g.vexs[k0]; //v0∈V-Up.vexs[n++]=v0;s+=closest[k0].lowcost;//求最小生成树的权值之和 cout<<"从编号为 "<<u0<<" 的城市到编号为 "<<v0<<" 的城市"<<"的权值为"<<closest[k0].lowcost<<endl; //输出最小生成树的路径 closest[k0].lowcost=0;//将顶点v0纳入U集合for(i=0;i<g.n;i++)//在顶点v0并入U之后,重新选择最小边 if(g.city[k0][i].weight<closest[i].lowcost){closest[i].lowcost=g.city[k0][i].weight;closest[i].vex=v0;}}cout<<"\n最小生成树的权值之和为:"<<s<<endl;}void display(MGraph &g) //输出邻接矩阵算法{int i,j;for(i=0;i<g.n;i++){for(j=0;j<g.n;j++)if(g.city[i][j].weight==INF)cout<<"\t"<<"∞";elsecout<<"\t"<<g.city[i][j].weight;cout<<endl;}}void main() //主函数{int st;MGraph g;cout<<"\n*********************n个城市的最小生成树*****************"<<endl;CreateMap(g);{cout<<"\n该图所对应的邻接矩阵如下:"<<endl;display(g);cout<<endl<<"请输入起点城市编号:";cin>>st;while(1){if(st==0) break;else if(st>g.n)cout<<"输入起点城市编号有错,请重新输入!"<<endl;else{prim(g,st);cout<<"\n*************************************************"<<endl;}cout<<endl<<"请继续输入起点城市,否则输入0退出!"<<endl;cin>>st;}}}。