1、沈阳航空航天大学课 程 设 计 报 告课程设计名称:数据结构课程设计课程设计题目:Prim 算法求最小生成树院(系):计算机学院专 业: 计算机科学与技术(物联网方向)班 级:学 号:姓 名:指导教师: - 0 -学术诚信声明 本人声明:所呈交的报告(含电子版及数据文件)是我个人在导师指导下独立进行设计工作及取得的研究结果。尽我所知,除了文中特别加以标注或致谢中所罗列的内容以外,报告中不包含其他人己经发表或撰写过的研究结果,也不包含其它教育机构使用过的材料。与我一同工作的同学对本研究所做的任何贡献均己在报告中做了明确的说明并表示了谢意。报告资料及实验数据若有不实之处,本人愿意接受本教学环节“不
2、及格”和“重修或重做”的评分结论并承担相关一切后果。 本人签名: 日期: 2015 年 1 月 15 日- 1 -沈阳航空航天大学课 程 设 计 任 务 书课程设计名称 数 据 结 构 课 程 设 计 专 业计算机科学与技术(物联网方向)学生姓名 班级 学号题目名称 Prim 算法生成最小生成树起止日期 2015 年 1 月 5 日起至 2015 年 1 月 16 日止课设内容和要求:在 n 个城市之间建立网络,只需保证连通即可,求最经济的架设方法,利用Prim 算法输出 n 个城市之间网络图,输出 n 个节点的最小生成树。其中,n 个城市表示 n 个节点,两个城市间如果有路则用边连接,生成一
3、个 n 个节点的边权树,要求键盘输入。参考资料:算法与数据结构,严蔚敏、 吴伟民,清华大学出版社,2006C 语言程序设计,谭浩强,清华大学出版社,2010教 研 室 审 核 意 见 : 教 研 室 主 任 签 字 :指导教师(签名) 年 月 日- 2 -学 生(签名) 2015 年 1 月15 日- 3 -目 录学术诚信声明 - 1 -一 课程设计目的和要求 - 4 -1.1 课程设计目的 .- 4 -1.2 课程设计的要求 .- 4 -二 实验原理分析 - 5 -2.1 最小生成树的定义 .- 5 -2.2 PRIM 算法的基本思想 - 5 -三 概要分析和设计 - 7 -3.1 概要分析
4、 .- 7 -3.2 概要设计 .- 8 -四 测试结果 - 13 -4.1 实验一 .- 13 -4.2 实验二 .- 13 -4.3 实验三 .- 14 -参考文献 - 15 -附 录(关键部分程序清单) - 16 - 4 -一 课程设计目的和要求1.1 课程设计目的(一) 根据算法设计需要,掌握连通网的数据表示方法;(二) 掌握最小生成树的 Prim 算法;(三) 学习独立撰写报告文档。1.2 课程设计的要求在 n 个城市之间建立网络,只需保证连通即可,求最经济的架设方法,利用Prim 算法输出 n 个城市之间网络图,输出 n 个节点的最小生成树。其中,n 个城市表示 n 个节点,两个城
5、市间如果有路则用边连接,生成一个 n 个节点的边权树,要求键盘输入。- 5 -二 实验原理分析2.1 最小生成树的定义一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或 Prim(普里姆)算法求出。(1). 最小生成树的概述在一给定的无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得 w(T) 最小,则此 T 为 G 的最小生成树。最小生成树其实是最小权重
6、生成树的简称。(2). 最小生成树的分析构 造 最 小 生 成 树 可 以 用 多 种 算 法 。 其 中 多 数 算 法 利 用 了 最 小 生 成 树 的下 面 一 种 简 称 为 MST 的 性 质 : 假 设 N=(V,E)是 一 个 连 通 网 , U 是 顶点 集 V 的 一 个 非 空 子 集 。 若 (u,v)是 一 条 具 有 最 小 权 值 ( 代 价 ) 的 边 , 其中 u U, v V-U, 则 必 存 在 一 棵 包 含 边 (u.v)的 最 小 生 成 树 。2.2 Prim 算法的基本思想假设 G =(V,E)是一个具有 n 个顶点的连通网,T=(U,TE)是
7、G 的最小生成树,其中 U 是 T 的顶点集,TE 是 T 的边集,U 和 TE 的初值均为空集。算法开始时,首先从 V 中任取一个顶点(假定取 V0) ,将它并入 U 中,此时 U=V0,然后只要 U 是 V 的真子集,就从那些其一个端点已在 T 中,另一个端点仍在 T 外的所有边中,找一条最短(即权值最小)边,假定为(i,j) ,其中 ViU,Vj(V-U),并把该边(i,j)和顶点 j 分别并入 T 的边集 TE 和顶点集 U,如此进行下去,每次往生成树里并入一个顶点和一条边,直到 n-1 次后就把所有 n 个顶点都并入到- 6 -生成树 T 的顶点集中,此时 U=V,TE 中含有 n-
8、1 条边,T 就是最后得到的最小生成树。可以看出,在普利姆算法中,是采用逐步增加 U 中的顶点,常称为“加点法” 。为了实现这个算法在本设计中需要设置一个辅助数组 closedge ,以记录从 U 到 V-U 具有最小代价的边。当辅助数组中存在两个或两个以上的最小代价的边时,此时最小生成树的形态就不唯一,此时可以在程序中采用递归的算法思想求出每个最小生成树。(1). 在 prim 算法中要解决两个问题1) 在无向网中,当从一个顶点到其他顶点时,若其边上的权值相等,则可能从某一起点出发时,会得到不同的生成树,但最小生成树的权值必定相等,此时我们应该如何把所有的最小生成树求解出来;2) 每次如何从
9、生成树 T 中到 T 外的所有边中,找出一条权值最小的边。例如,在第 k 次(1kn-1)前,生成树 T 中已有 k 个顶点和 k-1 条边,此时 T 中到 T 外的所有边数为 k(n-k),当然它也包括两顶点间没有直接边相连,其权值被看作常量的边在内,从如此多的边中找出最短的边,其时间复杂度0(k(n-k) ) ,是很费时间的,是否有好的方法能够降低查找最短边的时间复杂度。(2). 上述问题的解决方法针对 1)中出现的问题,可以通过算法来实现,详情请看 Prim 算法的概述;针对 2)中出现的问题,通过对 Prim 算法的分析,可以使查找最短边的时间复杂度降低到 O(n-k)。具体方法是假定
10、在进行第 k 次前已经保留着从 T 中到 T 外的每一顶点(共 n-k 个顶点)的各一条最短边,进行第 k 次时,首先从这 n-k 条最短边中,找出一条最最短的边,它就是从 T 中到 T 外的所有边中的最短边,假设为(i,j) ,此步需进行 n-k 次比较;然后把边(i,j)和顶点 j 分别并入 T 中的边集 TE 和顶点集 U 中,此时 T 外只有 n-(k+1)个顶点,对于其中的每个顶点 t,若(j,t )边上的权值小于已保留的从原 T 中到顶点 t 的最短边的权值,则用(j,t)修改之,使从 T 中到 T 外顶点 t 的最短边为(j,t) ,否则原有最短边保持不变,这样,就把第 k 次后
11、从 T 中到 T 外每一顶点 t 的各一条最短边都保留下来了,为进- 7 -行第 k+1 次运算做好了准备,此步需进行 n-k-1 次比较。所以,利用此方法求第k 次的最短边共需比较 2(n-k)-1 次,即时间复杂度为 O(n-k)。- 8 -三 概要分析和设计3.1 概要分析通过对上述算法的分析,将从以下三方面来进行分析:(1). 输入数据的类型在本次设计中,是对无向图进行操作,网中的顶点数,边数,顶点的编号及每条边的权值都是通过键盘输入的,他们的数据类型均为整型,其中,权值的范围为 032768(即“” ) ;(2). 输出数据的类型当用户将无向图创建成功以后,就可以通过键盘任意输入一个
12、起点值将其对应的最小生成树的生成路径及其权值显示出来;(3). 测试数据本次设计中是通过用 Prim 算法求最小生成树,分别用以下三组数据进行测试:(一) 假设在创建无向图时,只输入一个顶点,如图 1 所示,验证运行结果;图 1.单一节点的无向图(二) 假设创建的无向图如图 2 所示,验证运行结果;A- 9 -图 2.网中存在权值相等的边(三) 假设创建的无向图如图 3 所示,验证结果;图 3,网中的权值各不相等3.2 概要设计在本次设计中,网的定义为 G=(V,E),V 表示非空顶点集,E 表示边集,其存储结构这里采用邻接矩阵的方式来存储。 1 数据类型的定义 在本设计中所涉及- 10 -到
13、的数据类型定义如下:(1). 符号常量的定义算法中涉及到两个符号常量,定义如下:#define MAX 20 功能:用于表示网中最多顶点个数;#define INFINIT 32768 功能:用于表示权的最大值,即。(2). 结构体的定义 整个算法中涉及的结构体定义如下: 定义结构体 ArcNode功能:用于存放边的权值 typedef struct int adj;/权值 ArcNode; 定义结构体 AdjMatrix 功能:用于表示网的结构及存储方式。 typedef struct int vexsMAX;/vexs 表示顶点向量 int vexnum,arcnum;/分别表示图的顶点数
14、和弧数 ArcNode arcsMAXMAX;/邻接矩阵 AdjMatrix 定义结构体 Node 功能:用于表示求最小生成树时用到的辅助数组。 typedef struct int adjvex;/存放顶点编号 int lowcost;/存放顶点权值 Node; 外部变量的定义 算法中涉及到两个外部变量,定义如下: - 11 -Node closeMAX 功能:存放每个顶点所连接的边所对应的权值; int flag=0 功能:标志变量,当创建网时,输入的顶点个数vexnum),其中,调用函数 Minium()求出辅助数组 close中权值最小的边, 并将其在辅助数组中的相应位置返回到主调函数
15、中并赋给 k0,此时 closek0中存有当前最小边(u0, v0)的信息,将边所对应的终点放入 p 的顶点向量表中,累加边的权值;然后,输出;最后,在顶点 v0 并入 U 之后,利用 for 循环更新closedgei;当所有的顶点 v0 都纳入 U 集合之后,输出最小生成树中的顶点序列及最小生成树的权值之和。五、 子函数 void display(AdjMatrix *G) 功能:是创建的无向网所对应的邻接矩阵;六、 主函数 void main() 功能:是完成对上述各子函数的调用,完成本次设计的要求,在其函数体中,通过 while 循环可以实现重复创建网以及可以从网中的不同顶点出发求出对
16、应的最小生成树。(4). 流程图- 13 -开始输入 ch, 用于判断是否创建无向网Ch=“Y”结束输入起点 st1调用 create()函数2调用 display()函数Flog=0st=03调用 prim()函数4调用 minium()函数图 4.流程图上述流程图反映了整个算法中各个子函数之间的嵌套调用,从主函数开始顺序往下执行,首先调用 creat()函数创建无向网并采用邻接矩阵的方式来存储;然后将该网对应的邻接矩阵通过调用 display()函数输出;最后调用 prim ()函数求出该网所对应的最小生成树,并且在 prim ()函数中通过嵌套调用 Minium ()函数求出辅助数组 c
17、lose中权值最小的边,从而完成了本设计的要求。- 14 -四 测试结果该部分是对前面任务定义中的测试数据进行验证和分析:4.1 实验一只含一个顶点的无向图。图 5. 只含一个顶点的无向图4.2 实验二假定创建的无向网的顶点个数1,并且网中有些边的权值相等。- 15 -图 7.运行结果分析:在上述创建的无向网中,有些顶点之间没有边相连接,所以在邻接矩阵中用表示,由于是以顶点 1 作为起点生成最小生成树,所以上述运行结果对应的生成树如图 7 所示。4.3 实验三假定创建的无向网的顶点个数1,并且网中有些边的权值不相等。运行结果如下:- 16 -参考文献(1). 吴玉蓉,数据结构(C 语言版) ,
18、中国水利水电出版社,2008 年;(2). 徐孝凯,数据结构实用教程,清华大学出版社,2005 年 7 月;(3). 谭浩强,C 语言程序设计教程,高等教育出版社,2004 年 5 月。- 17 -附 录(关键部分程序清单)#include“stdio.h“#include“string.h“ #include“malloc.h“ #include“iostream.h“#include“iomanip.h“ #define MAX 20 /最多顶点个数 #define INFINIT 32768/表示极大值,即 typedef struct int adj; /adj 是权值类型 ArcNo
19、de; typedef struct int vexsMAX,vexnum,arcnum; /*vexs 表示顶点向量;vexnum,arcnum 分别表示图的顶点数和弧数*/ ArcNode arcsMAXMAX; /*邻接矩阵*/ AdjMatrix; typedef struct int adjvex;/存放顶点编号 int lowcost;/存放顶点权值 Node; Node closeMAX;/求最小生成树时的辅助数组 int flag=0; /功能:标志变量,当创建网时,输入的顶点个数vexnum;k+) if(G-vexsk=V) j=k;- 18 -break; return
20、j; AdjMatrix *creat(AdjMatrix *G) /创建无向网 int i,j,k,v1,v2,weight,m=1; printf(“请输入网中的顶点数:“); scanf(“%d“, if(G-vexnumarcnum); for(i=0;ivexnum;i+) /初始化邻接矩阵 for(j=0;jvexnum;j+) if(i=j) G-arcsij.adj=0; else G-arcsij.adj=INFINIT; printf(“请输入网中的顶点编号:“); / 输入网中的顶点编号 for(i=0;ivexnum;i+)scanf(“%d“, printf(“输入每
21、条弧所对应的两个顶点及权值!n“); for(k=0;karcnum;k+) printf(“请输入第%d 条边:“,m);m+;scanf(“%d %d %d“, /输入一条弧的两个顶点及权值 i=Locate(G,v1); j=Locate(G,v2); G-arcsij.adj=weight; G-arcsji.adj=weight; return(G); - 19 - int Minium(AdjMatrix *G,Node close)/close中权值最小的边 int i,min,k; min=INFINIT;/置最小权值为 INFINIT for(i=0;ivexnum;i+)
22、if(closei.lowcostvexsn+=u; closek.lowcost=0;/初始化 U=u for(i=0;ivexnum;i+) if(i!=k) /对 V-U 中的顶点 i,初始化 closei closei.adjvex=u; closei.lowcost=G-arcski.adj; for(j=1;jvexnum-1;j+)/n-1 条边(n=G-vexnum) k0=Minium(G,close);/closek0中存有当前最小边(u0, v0)的信息 u0=closek0.lowcost;/u0U v0=G-vexsk0; /v0V-U p-vexsn+=v0;/将终
23、点放入数组中 s+=closek0.lowcost;/求最小生成树的权值之和 printf(“ %dt%dn“,u,v0,closek0.lowcost); /输出最小生成树的路径 closek0.lowcost=0;/将顶点 v0 纳入 U 集合 for(i=0;ivexnum;i+)/在顶点 v0 并入 U 之后,更新 closedgei- 20 -if(G-arcsk0i.adjarcsk0i.adj; closei.adjvex=v0; printf(“n 最小生成树中的顶点序列为: “);for(i=0;ivexnum;i+)printf(“ %d “,p-vexsi); print
24、f(“n“);printf(“n 最小生成树的权值之和为: %dn“,s);void display(AdjMatrix *G) /输出邻接矩阵算法 int i,j; for(i=0;ivexnum;i+)printf(“t%d“,G-vexsi);printf(“n“); printf(“); for(i=0;ivexnum;i+)printf(“);printf(“n“);for(i=0;ivexnum;i+)printf(“ %d “,G-vexsi); for(j=0;jvexnum;j+)if(G-arcsij.adj=INFINIT)printf(“t“); elseprintf(
25、“t%d“,G-arcsij.adj);printf(“n“);for(i=0;ivexnum;i+)printf(“);printf(“n“);void main() /主函数 char ch; int st; - 21 -AdjMatrix *G,*p; p=(AdjMatrix *)malloc(sizeof(AdjMatrix); printf(“*n“); printf(“ 普里姆最小生成树算法! n“); printf(“n*n“); printf(“ 设 计 者:李浩渊n“); printf(“ 班 级:34010105 班 n“); printf(“ 指导老师:范纯龙老师 n“
26、); printf(“ 设计时间:2015 年 1 月 15 日n“); printf(“n*“); printf(“n*若创建无向网请输入Y,否则按任意键!*n“);scanf(“%c“, while(1)if(ch=Y|ch=y) G=creat(p); if(flag=0) printf(“n*该无向网所对应的邻接矩阵如下*n“); display(G); printf(“请输入起点:“); scanf(“%d“, while(1) if(st=0) break; else if(stG-vexnum) printf(“-输入起点有错,请重新输入 !-n“); else printf(“
27、-利用普里姆算法从起点 %d 出发,最小生成树的路径如下-nn“,st); printf(“n*n“); printf(“终点 权值nn“); prim(G,st); printf(“n*n“); printf(“请继续输入起点,否则输入 0 退出 !“); scanf(“%d“, - 22 - printf(“n*继续创建无向网请输入Y,否则按任意键!*“); scanf(“%c“, flag=0; else break; 沈阳航空航天大学-24-课程设计总结和体会:在整个课程设计的过程中,首先,应该根据课题的要求对题意进行分析,将所遇到的问题进行归纳和总结,在本设计中,题意要求对给定的网和
28、起点,用 PRIM 算法的基本思想求解出所有的最小生成树,我们应该了解关于网的一些基本概念和生成树与最小生成树之间有何区别和联系,主要是要明确的理解PRIM 算法的基本思想。其次,针对出现的问题查找相关资料将其解决,主要应该查找有关 PRIM 算法基本思想方面的详细介绍,当所有的问题得到解决后,对本设计应该有个整体的思路并通过编写各个函数模块去实现课题的功能;最后,将编写的源程序代码在计算机上调试运行,直至调试成功。 本次课程设计,让我对所学的知识有了一次综合运用的机会,通过实践,提高了自己在分析问题、解决问题和编写算法方面的能力,从而对所学的知识有了更加深刻的理解和掌握,受益匪浅。希望以后学校能多提供这样的机会给我们锻炼,使我们能够为学所用,真正增长我们的才干。