数据结构课程设计报告Word格式文档下载.docx
《数据结构课程设计报告Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告Word格式文档下载.docx(21页珍藏版)》请在冰豆网上搜索。
本课程设计是以邻接矩阵作为图的存储结构,分别采用Prim和Kruskal算法求最小生成树。
Kruskal算法和Prim算法是求最小生成树的常用算法它们分别适用于稠密图和稀疏图。
最小生成树的应用非常的广,如矿井通风设计和改造最优化方面以及如何搭建最短的网络线缆,
构建造价最低的通讯网络
。
一、引言
本课程设计我们要解决的问题是图最小生成树问题。
要用到图的先相关数据结构和求最小生成树的两种数据结构算法普里姆算法和克鲁斯卡尔算法,以及储存图的边和点的邻接矩阵。
本课程设计要解决的问题构造连通网的最小生成树
我们首先要做的是创建一个邻接矩阵,用以来存储图,然后我们要想好怎样利用普里姆算法和克鲁斯卡尔算法来构造最小生成树。
把这两种算法写入主函数,调试好程序。
最后写好报告。
二、设计题目
1.问题描述
若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。
如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
2.系统要求
利用克鲁斯卡尔算法求网的最小生成树。
利用普里姆算法求网的最小生成树。
要求输出各条边及它们的权值。
3.测试数据
4.实现提示
通信线路一旦建成,必然是双向的。
因此,构造最小生成树的网一定是无向图。
设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数,100则表示没有路径。
5.参考文献
[1]
严蔚敏.
数据结构(C语言版)[M].
北京:
清华大学出版社,1997.
[2]
谭浩强.
C程序设计(第三版)[M].
清华大学出版社,2005.1.
[3]
二霍红卫算法设计与分析〔」西安西安电子科技大学出版社,2005.113-127.
[4]
陈杰.计算机专业课程设计中的需求分析[J].集美大学学报,2009,10
(2):
89—92.
[5]
高一凡.
数据结构算法实现及解析[M
].
西安:
西安电子科技大学出版社,
2002
6.运行环境
VC++6.0
三、需求分析
此问题的关键在于如何实现PRIM算法和Kruskal算法,实现的过程中如何得到构成最小生成树的所有顶点,此外输出也是一个关键问题所在,在此过程中经过了多次调试。
将图中的所有顶点存储到一个一维数组中,通过一个二维数组用邻接矩阵连实现对各边权值的存储
首先我们对prim算法的问题进行大致的概要分析:
假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。
算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。
此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。
克鲁斯卡尔算法从另一种途径求网的最小生成树:
假设连通网N=(V,{E}),则另最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择代价最小的边若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。
以此类推直至T中的所有顶点都在同一连通分量上为止。
对于prim算法从图的点集中任取一个顶点作为起始顶点,然后找到依附于该顶点的所有边选取权值最小的,依次找下去直至图中所有顶点都在一个点集中为止。
对于克鲁斯卡尔算法则通过对权值进行排序找出权值最小的顶点和边并把该边的顶点并入点集之中。
通过访问数组来实现对最小生成树边和权值的输出。
四、概要设计
1、设定图的抽象数据类型:
ADT
Graph{
数据对象V:
V是具有相同特性的数据元素的集合,称为点集.
数据关系R:
R={VR}
VR={(v,w)|v,w属于V,(v,w)表示v和w之间存在的路径}
基本操作P:
CreatGraph(&
G,V,VR)
初始条件:
V是图的顶点集,VR是图中弧的集合.
操作结果:
按V和VR是定义构造图G.
Sort(edge*
MGraph
*)
图G存在,各边权值已知;
对权值进行排序;
Find(int
*,
int
)
前者为已存在的集合,后者为集合中的元素;
查找函数,确定后者所属子集;
Swapn(edge
int,
int)
交换某两个边的权值;
2.图的存储结构
typedefstruct
{
intvexnum,arcnum;
}ALGraph;
typedefstruct//边的结构体定义
intbegin,end;
//边的开始和结束顶点
intcost;
//权值
}EDGE;
{
intedges[max][max];
//
intn,e;
}MGraph;
3.流程图
五、详细设计
在该函数中有6个模块,分别是主函数模块、路径权值进行排序、交换顶点及权值模块、判断是否回环、prim算法的实现、Kruskal算法的实现。
1.主函数模块
ALGraphG;
MGraphG2;
intv,i,j;
chara;
do
{
system("
cls"
);
cout<
<
"
\t***********************************\n\n"
;
\t1克鲁斯卡尔\n"
\t2普里姆\n"
\t3退出\n\n"
\t***********************************\n"
请输入序号:
cin>
>
a;
switch(a)
{
case'
1'
:
MiniSpanTree_Kruskal(G);
system("
pause"
break;
2'
cout<
请输入结点数:
cin>
G2.n;
for(j=1;
j<
=G2.n;
j++)
{
cout<
请输入第"
个顶点所有边的权值(100代表不连通):
for(i=1;
i<
i++)
G2.edges[j][i];
}
请输入开始顶点:
v;
MiniSpanTree_PRTM(G2,v);
default:
break;
}
}while(a!
='
3'
return0;
该模块包含菜单的设计以及通过一个switch语句来实现对prim算法和Kruskal算法的实现。
进入主菜单后选择相应的序号执行相应的操作,每进行一步后,按任意键继续进行下一个操作可重复执行。
2.对路径权值进行排序
voidSort(EDGE*edges,ALGraphG)
//对带权路径从小到大排序
inti,j;
for(i=1;
=G.arcnum;
for(j=i;
if(edges[i].cost>
edges[j].cost)
Swapn(edges,i,j);
}
在图中找到权值最小的边
3.交换顶点及权值
voidSwapn(EDGE*edges,inti,intj)//交换的两个顶点及权值
inttemp;
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].cost;
edges[i].cost=edges[j].cost;
edges[j].cost=temp;
该模块主要用于Kruskal算法,找到图中权值最小的一条边,然后交换它们的顶点和权值。
4.判断是否回环
intFind(int*parents,intf)
//判断是否形成环
while((parents[f])>
0&
&
(f!
=parents[f]))
f=parents[f];
returnf;
在Kruskal算法中初始parents[]为0来设置访问未访问标志,以此来判断图是否成环。
5.prim算法的实现
voidMiniSpanTree_PRTM(MGraph&
G,intv)
intclosedge[max];
intlowcost[max];
inti,j,k,min;
=G.n;
lowcost[i]=G.edges[v][i];
closedge[i]=v;
}
G.n;
min=INF;
for(j=1;
if(lowcost[j]!
=0&
lowcost[j]<
min)
min=lowcost[j];
k=j;
printf("
边(%d,%d)权为:
%d\n"
closedge[k],k,min);
lowcost[k]=0;
if(G.edges[k][j]!
G.edges[k][j]<
lowcost[j])
lowcost[j]=G.edges[k][j];
closedge[j]=k;
6.Kruskal算法的实现
voidMiniSpanTree_Kruskal(ALGraph&
G)
//MiniSpanTree_Kruskal()函数实现
inti,s,v1,v2,value,bnf,edf;
intparents[MAX_VERTEX_NUM];
EDGEedges[MAX_VERTEX_NUM];
endl<
请输入顶点数:
"
cin>
G.vexnum;
//输入顶点数
请输入边数:
G.arcnum;
//输入边数
请输入(V1和V2),例如:
(V1=1,V2=3),(V1=2,V2=4)..."
endl;
//输入arc(v1,v2)
++i)
请输入第"
条边的第一个顶点:
v1;
//输入头顶点
条边的第二个顶点:
v2;
//输入尾顶点
条边的权值:
value;
//输入边的权值
edges[i].begin=v1;
edges[i].end=v2;
while(v1<
1||v1>
G.vexnum||v2<
1||v2>
G.vexnum)//如果输入的非法,重新输入
输入不合法,请重新输入!
edges[i].begin=v1;
edges[i].end=v2;
edges[i].cost=value;
}
Sort(edges,G);
//调用Sort()函数
按照排列好的序列逐个输出权值"
edges[i].cost<
\t"
=G.vexnum;
parents[i]=0;
//初始化arrayparents[]
最小生成树为:
for(i=1,s=1;
s<
=G.vexnum&
{
bnf=Find(parents,edges[i].begin);
edf=Find(parents,edges[i].end);
if(bnf!
=edf)
parents[bnf]=edf;
edges[i].begin<
-"
//输出最小生成树
edges[i].end<
的边为:
edges[i].cost;
s++;
}
}
六、调试与分析
测试数据如下图
求该图的最小生成树
1.进入主页面
2.利用克鲁斯卡尔算法求最小生成树
选择序号1使用克鲁斯卡尔算法求图的最小生成树。
输入每条边的顶点和权值
对权值进行排序,并且输出最小生成树。
3.利用prim算法求最小生成树
选择序号2用prim算法求最小生成树。
通过一个n阶的邻接矩阵来实现图的输入
输入起始顶点然后输出最小生成树的各边及其每一条边的权值。
4.退出程序
选择序号3退出程序
七、测试结果
克鲁斯卡尔算法求得的最小生成树为352146
Prim算法求得的最小生成树为125346
八、设计心得体会
在我的努力下,课程设计终于完成,由于我们对数据结构和c语言不是很了解,有时忽略了一些关键的细节,使得在编写程序的过程中出现了一些问题。
对于打字有时粗心导致出现一些难以发现的小错误,在我的耐心,细致的调试下最终使得程序能够运行,课程设计圆满完工。
问题一:
求出图中的最小值
现象:
求出的最小值是0
原因:
图中没有连通的两个顶点之间的权值赋值为0
问题二:
求最小生成树时,else语句需再调用一个函数
对某些二叉树能求出最小生成树,但不能普遍适应
对于找最小生成树边的各种可能没有考虑全面,代码才没有广泛的适应性
问题三:
两个顶点之间的边是否是最小生成树的边
代码的功能不能分辨出是否是最小生成树的边
把简单的代码写的很复杂,从而杂乱无章出现错误。
在课设过程中,遇到许多问题,通过查阅资料和课本。
是我对数据结构有了更进一步的认识。
当然,这中间也有其他人的帮助。
我的同学,以及指导老师都给我提出了非常宝贵的意见。
通过与同学和老师的交流,使我找到了数据结构这门课程的学习方法。
但是,我感觉这不仅仅是数据结构的学习方法,他或许就是学习软件工程这门专业的方法,那就是多动手。
的确如此,对于一个算法,你知道它的算法思想和用计算机实现它却是另外一回事。
这门课程,不仅需要我们用心去理解每一种算法的思想,更需要我们去动手来实现它。
附录(源代码)
#include"
iostream"
usingnamespacestd;
#defineMAX_VERTEX_NUM30//定义最大顶点数
#defineMAXQSIZE100
#definemax20
#defineINF10
//////////////////////////////
voidSwapn(EDGE*edges,inti,intj);
//交换的两个顶点及权值
voidSort(EDGE*edges,ALGraphG);
//对带权路径从小到大排序
intFind(int*parents,intf);
//判断是否形成环
G);
//MiniSpanTree_Kruskal()函数实现
///////////////////////
G.n