数据结构课程设计报告最小生成树.docx
《数据结构课程设计报告最小生成树.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告最小生成树.docx(12页珍藏版)》请在冰豆网上搜索。
数据结构课程设计报告最小生成树
《数据结构》期末课程设计
题目第8题:
最小生成树问题
学院计算机学院
专业
班别
学号
姓名陈聪
2015年7月6日
一、需求分析
1、问题描述
若要在n个城市之间建设通讯网络,只需要架设n-1条线路即可。
如何以最低的经济代价建设这个通讯网,是一个网的最小生成树问题。
2、基本要求
(1)利用克鲁斯卡尔算法求网的最小生成树。
(2)实现并查集。
以此表示构造生成树过程中的连通分量。
(3)以文本形式输出生成树中各条边以及他们的权值。
3、实现提示
通讯线路一旦建立,必然是双向的。
因此,构造最小生成树的网一定是无向网。
设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数,可利用C语言提供的随机数函数产生。
图的存储结构的选取应和所作操作向适应。
为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组即边集数组表示图。
2、详细设计
根据课设题目要求,拟将整体程序分为三大模块,分别是:
图的存储结构,并查集的实现,克鲁斯卡尔算法的实现。
1、边集数组的类型定义:
typedefstruct
{
intx,y;
intw;
}edge;
x表示起点,y表示终点,w为权值。
2、并查集功能的实现由以下函数实现:
Make_Set(intx)初始化集合;
Find_Set(intx)查找x元素所在的集合,回溯时压缩路径;
Union(intx,inty,intw)合并x,y所在的集合。
3、克鲁斯卡尔算法的实现
该算法的实现位于主函数中:
qsort(e,n,sizeof(edge),cmp);//将边排序
printf("最小生成树的各条边及权值为:
\n");
for(i=0;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坐标)非降序排序*/
intcmp(constvoid*a,constvoid*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(unsignedintseed);
使用随机数函数如下:
srand((unsigned)time(NULL));
for(i=0;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。
5、主程序的流程图
三、调试分析
调试过程中遇到的问题:
随机产生权值时,通过边数不能确定起点和终点。
解决:
通过顶点数对所有边取随机数。
四、用户使用说明及测试结果
1、打开界面:
(1)人为输入权值,输入1,回车:
输入7,回车:
输入边的信息及结果如下:
(2)随机生成权值,输入0:
输入顶点数5,结果如下:
五、经验和体会
通过本次课程设计,我学会了利用克鲁斯卡尔算法求最小生成树。
另外学会了利用随机函数产生随机数,以及课本没有提到的边集数组的定义和使用。
六、附录源代码
#include
#include
#include"time.h"
#defineMAX435
/*定义边(x,y),权为w*/
typedefstruct
{
intx,y;
intw;
}edge;
edgee[MAX];
/*rank[x]表示x的秩*/
intrank[MAX];
/*father[x]表示x的父节点*/
intfather[MAX];
/*比较函数,按权值(相同则按x坐标)非降序排序*/
intcmp(constvoid*a,constvoid*b)
{
if((*(edge*)a).w==(*(edge*)b).w)
{
return(*(edge*)a).x-(*(edge*)b).x;
}
return(*(edge*)a).w-(*(edge*)b).w;
}
/*初始化集合*/
voidMake_Set(intx)
{
father[x]=x;
rank[x]=0;
}
/*查找x元素所在的集合,回溯时压缩路径*/
intFind_Set(intx)
{
while(father[x])
{
x=father[x];
}
returnx;
}
/*合并x,y所在的集合*/
voidUnion(intx,inty,intw)
{
if(x==y)return;
/*将秩较小的树连接到秩较大的树后*/
if(rank[x]>rank[y])
{
father[y]=x;
}
else
{
if(rank[x]==rank[y])
{
rank[y]++;
}
father[x]=y;
}
}
/*主函数*/
intmain()
{
printf("*最小生成树问题:
\n");
inti,n,h,k=0;
intx,y;
charchx,chy;
printf("\n人为输入权值请输入1,随机生成权值请输入0:
\n");
scanf("%d",&k);
if(k==1)
{
/*读取边的数目*/
printf("请输入边的条数(小于436):
\n");
scanf("%d",&n);
getchar();
/*读取边信息并初始化集合*/
printf("请输入边的信息(起点,终点,权值(<100))分别用空格隔开:
\n");
for(i=0;i{
scanf("%c%c%d",&chx,&chy,&e[i].w);
getchar();
e[i].x=chx-'A';
e[i].y=chy-'A';
Make_Set(i);
}
}
else{
printf("请输入顶点数(<=30):
\n");
scanf("%d",&h);
getchar();
srand((unsigned)time(NULL));
n=(h-1)*h/2;chx=49;chy=50;
for(i=0;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);
}
printf("随机生成的各条边及权值为:
\n");
for(i=0;i{
printf("%c-%c:
%d\n",e[i].x+'A',e[i].y+'A',e[i].w);
}
}
/*将边排序*/
qsort(e,n,sizeof(edge),cmp);
printf("最小生成树的各条边及权值为:
\n");
for(i=0;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);
}
}
return0;
}