数据结构课程设计报告.docx
《数据结构课程设计报告.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告.docx(26页珍藏版)》请在冰豆网上搜索。
数据结构课程设计报告
《数据结构》
课程设计报告
2015年6月
一、构造n个城市连接的最小生成树
1、问题描述
一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
基本要求:
(1)城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。
要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
(2)表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)
2、设计思路
这个问题主要通过PRIM的基本算法实现求最小生成树,该算法的主要思想是:
设置两个辅助一维数组lowcost和closevertex,其中lowcost同来保存集合V-U中各顶点与集合U中各顶点构成的边中具有最小权值的边的权值;数组closevertex用来保存依附于该边的在集合U中的顶点。
假设初始状态时,U=(u0)(u0为出发的顶点),这时有lowcost[0]=0;它表示顶点u0已加入集合U中,数组lowcost的其他各分量的值是顶点u0到其余各顶点所构成的直接边的权值。
然后不断选区权值最小的边(ui,uk),每选取一条边,就将lowcost(k)置为0,表示顶点uk已加入集合U中。
优于顶点uk从集合V-U进入集合U后,这两个集合的内容发生了变化,就要依据具体情况更新数组lowcost和closevertex中部分分量的内容。
最后closevertex中即为所建立的最小生成树。
3、数据结构定义
#defineINFINITY30000//定义一个权值的最大值
#defineMaxVertexNum30//图的最大顶点数为30
typedefstruct
{
intn,e;//城市数和道路数
intedges[MaxVertexNum][MaxVertexNum];//邻接矩阵
}MGraph;
typedefstruct
{
intadjvertex;//某顶点与已构造好的部分生成树的顶点之间权值最小的顶点
intlowcost;//某顶点与已构造好的部分生成树的顶点之间的最小权值
}ClosEdge;//用PRIM算法求最小生成树时的辅助数组
4、系统功能模块介绍
输入城市数、道路数
G=(V,E)为一网图,建立无向图邻接矩阵
求最小生成树
辅助数组close_edge初始化;U={u}
for(i=0;i在辅助数组中选择权值最小的顶点k并将k并入U集,修改辅助数组
i是
否
最小生成树构造完毕
打印出最小生成树
的各条边及权值
5、程序清单
(1)创建城市间的邻接矩阵存储并输出矩阵
voidCreateMgraph(MGraph*G)//建立无向图G的邻接矩阵存储
{
inti,j;
intstart,end,weight;
printf("请输入城市数和道路数:
");
cin>>G->n>>G->e;
cout<<"n="<n<<",e="<e;
for(i=0;in;i++)//初始化邻接矩阵
for(j=0;jn;j++)
{
if(i==j)
G->edges[i][j]=0;
else
G->edges[i][j]=INFINITY;
}
cout<"<for(i=0;ie;i++)
{
cin>>start>>end>>weight;
G->edges[start][end]=weight;
G->edges[end][start]=weight;
}
cout<<"邻接矩阵为:
"<for(i=0;in;i++)//输出邻接矩阵
{
for(j=0;jn;j++)
{
if(G->edges[i][j]==INFINITY)
cout<<"∞"<<"";
else
cout<edges[i][j]<<"";
}
cout<}
}
(2)用PRIM算法求城市间的最小生成树并得到最小代价
voidMiniSpanTree_PRIM(MGraph*G,intu)
{
ClosEdgeclose_edge[MaxVertexNum];
inti,j,w,k;
inttotalCost=0;
for(i=0;in;i++)
if(i!
=u)
{
close_edge[i].adjvertex=u;
close_edge[i].lowcost=G->edges[u][i];
}
close_edge[u].lowcost=0;
for(i=0;in-1;i++)
{
w=INFINITY;
for(j=0;jn;j++)
if(close_edge[j].lowcost!
=0&&close_edge[j].lowcost{
w=close_edge[j].lowcost;
k=j;
}
close_edge[k].lowcost=0;
for(j=0;jn;j++)
{
if(G->edges[k][j]{
close_edge[j].adjvertex=k;
close_edge[j].lowcost=G->edges[k][j];
}
}
}
cout<<"打印最小代价生成树的各条边:
"<for(i=0;in;i++)
if(i!
=u)
{
cout<"<edges[i][close_edge[i].adjvertex]<totalCost=totalCost+G->edges[i][close_edge[i].adjvertex];
}
cout<<"总代价为:
"<}
(3)主函数
intmain()
{
intv;
MGraphG;
cout<<"***********构造n个城市连接的最小生成树问题***********"<cout<<"1.输入城市个数和道路数"<cout<<"2.输入相邻两城市和其间的距离"<cout<<"3.以邻接矩阵存储各个城市间的距离并输出矩阵"<cout<<"4.用PRIM算法得出n个城市连接的最小生成树"<cout<<"5.打印n个城市连接的最小生成树路径"<CreateMgraph(&G);
cout<<"请输入从哪个城市开始:
";
cin>>v;
MiniSpanTree_PRIM(&G,v);
return0;
}
6、运行及调试分析
1、调试分析
本程序的主要功能是对无向网进行邻接矩阵的初始化,然后用Prim算法求出城市间的最小生成树,得出最小代价。
Prim算法的思路是逐步将城市纳入生成树中,这里的关键步骤是要找到权值最小的顶点k,在PRIM算法中,第一个for循环的执行次数为n-1,第二个for循环中又包括一个while循环和一个for循环,执行次数为2(n-1)(n-1),所以PRIM算法的时间复杂度是O(n*n)。
由此可见,Prim算法与网中边数无关,适合求边稠密的网的最小生成树。
2、测试结果
(1)输入城市间信息
(2)输出城市间邻接矩阵
(3)打印最小生成树各条边及最小代价
7、课程设计总结
最小生成树主要由PRIM算法完成,通过整体构思,先确立了基本步骤:
1.建立一个具有n个顶点的无向图2.创建一个邻接矩阵来存储该图,然后初始化矩阵3.根据Prim算法,得到了最小生成树以及各边的权值。
在不断地努力下,完成了此这次课程设计的第一个任务。
本次实验,既巩固和加深了对数据结构的理解,认识到《数据结构》是计算机专业一门重要的专业技术基础课程,还提高了我综合运用本课程所学知识的能力,提高了我的组织数据及编写程序的能力。
而且在设计的过程中,并不是单纯的看看教材就能解决我们的实际问题,所以还要去查找各种我们所需要的资料。
要完成一个课程设计的课题并不是一次就能编译成功的,中间会出现很多的大问题小问题,改错是个很繁琐的问题。
通过这次课程设计培养了我独立思考,深入研究,分析问题,解决问题的能力。
2、运动会分数统计
一、问题描述
参加运动会有n个学校,学校编号为1……n。
比赛分成m个男子项目,和w个女子项目。
项目编号为男子1……m,女子m+1……m+w。
不同的项目取前五名或前三名积分;取前五名的积分分别为:
7、5、3、2、1,前三名的积分分别为:
5、3、2;哪些取前五名或前三名由学生自己设定。
(m<=20,n<=20)功能要求:
1)可以输入各个项目的前三名或前五名的成绩;
2)能统计各学校总分,
3)可以按学校编号、学校总分、男女团体总分排序输出;
4)可以按学校编号查询学校某个项目的情况;可以按项目编号查询取得前三或前五名的学校。
规定:
输入数据形式和范围:
20以内的整数(如果做得更好可以输入学校的名称,运动项目的名称)
输出形式:
有中文提示,各学校分数为整型
界面要求:
有合理提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。
2、设计思路
根据运动会分数统计系统的问题分析及要求,可以将此系统分为四个模块:
信息输入模块,信息统计模块,信息排序模块和信息查询模块。
(1)信息输入模块:
输入各个学校编号,项目编号,规定该项目取前3名还是前5名,然后输入此项目获得的名次数目以及获得的名次,得分由系统自动统计。
(2)信息统计模块:
主要用来统计各个学校获得的总分情况。
主要涉及函数tongjiScore()。
(3)信息排序模块:
可以对学生信息实现按学校编号,按学校总得分,按男团体总分,按女团体总分排序。
主要涉及函数Sort(),sort_schoolNum(),sort_score(),sort_maleScore(),sort_femaleScore()
(4)信息查询模块:
可以按学校编号查询学校某个项目情况,按项目编号查询取得名次的学校。
主要涉及函数Query_itemNum(),Query_schoolNum()。
3、数据结构定义
(1)项目数据表:
运动会开始前必须详细制定本次运动会所需的参赛项目为接下来报名、场地的准备提供依据。
该数据表包括每个项目的编号、取名次的数目、要取的名次以及各个名次对应的分数。
在初始输入时仅输入项目编号、取名次的数目及要取的名次,而各名次对应的分数将由系统自动统计。
#include
#include
usingnamespacestd;
#definen4//学校数目
#definem2//男子项目个数
#definew2//女子项目个数
typedefstruct
{
intitemNum;//项目编号
inttop;//取名次数目
intrange[5];//名次
intmark[5];//分数
}ItemNode;
(2)学校数据表:
该数据表存储了各个参赛学校的总体情况,包括学校的编号、男子团体总分、女子团体总分和学校总分。
其中学校编号是提前输入的,而其他三项内容将在输入得分以及名次等信息后由系统进行自动统计。
typedefstruct
{
intschoolNum;//学校编号
intscore;//学校总分
intmaleScore;//男团体总分
intfemaleScore;//女团体总分
ItemNodec[m+w];//项目数组
}SchoolNode;
SchoolNodes[20];
4、系统功能模块介绍
(1)总体设计
运动会分数统计系统
输入信息统计总分信息排序信息查询
按按按按按按
学学男女学项
校校团团校目
编总总总编编
号分分分号号
(2)信息输入及分数统计功能
voidinput()是信息输入函数,输入学校编号,项目编号、取名次的数目及要取的名次,而各名次对应的分数将由系统自动统计。
信息输入完后,可以用tongjiScore()函数统计各个学校总分。
开始
初始化数组s[i],
i=1;i<=n
输入学校编号、项目
编号、名次等信息
i++;i是
tongjiScore()
(2)信息排序功能
menu2(),sort_schoolNum(),sort_score(),sort_maleScore(),sort_femaleScore()是排序输出菜单函数以及四种排序输出。
输出一个菜单显示各种排序功能,利用switch语句实现按学校编号,按学校总分,按男团体总分,按女团体总分排序。
下图采用直接插入排序的方法实现按男团体总分由低到高输出。
开始
显示排序菜单,
选择排序功能
for(i=2;i<=n;i++)
while(s[0].maleScore0)N
Y
N交换数据
输出
结束
(3)信息查询功能
menu3(),Query_schoolNum(),Query_itemNum()函数是查询菜单函数以及两个信息查询函数。
显示主菜单,利用switch()语句选择功能,实现按学校编号查询某项目和按项目编号查询信息,并输出该学校某个项目情况或者某个项目取得前3或前5的学校信息。
按学校编号查询某项目功能如下:
开始
输入查询的学校编号
学校是否存在?
否
是
输入查询的项目编号提示错误,返回主菜单
项目是否存在?
否
是
循环查找;输出信息
结束
5、程序清单
(1)欢迎界面
voidmenu()
{cout<cout<<"(^o^)——————————————————————————(^o^)"<cout<<"(^o^)————————(^o^)"<cout<<"(^o^)————欢迎使用运动会分数统计系统!
————(^o^)"<cout<<"(^o^)————————(^o^)"<cout<<"(^o^)——————————————————————————(^o^)"<Sleep(1200);
system("cls");
}
(2)输入信息函数
voidinput()
{inti,j,k,t;
for(i=1;i<=n;i++)
{s[i].score=0;
s[i].maleScore=0;
s[i].femaleScore=0;
}
for(i=1;i<=n;i++)
{
cout<<"请输入第"<
";
cin>>s[i].schoolNum;
for(j=0;j{
cout<<"请输入项目编号(共"<";
cin>>s[i].c[i].itemNum;
cout<<"取前3名or前5名:
";
cin>>s[i].c[j].top;
cout<<"获得几个名次:
";
cin>>k;
for(t=0;t{
cout<<"请输入取得的名次:
";
cin>>s[i].c[j].range[t];
if(s[i].c[j].top==3)
switch(s[i].c[j].range[t])
{
case1:
s[i].c[j].mark[t]=5;break;
case2:
s[i].c[j].mark[t]=3;break;
case3:
s[i].c[j].mark[t]=2;break;
}
if(s[i].c[j].top==5)
switch(s[i].c[j].range[t])
{
case1:
s[i].c[j].mark[t]=7;break;
case2:
s[i].c[j].mark[t]=5;break;
case3:
s[i].c[j].mark[t]=3;break;
case4:
s[i].c[j].mark[t]=2;break;
case5:
s[i].c[j].mark[t]=1;break;
}
s[i].score=s[i].score+s[i].c[j].mark[t];//按取前三名还是取前五名分别记分
if(js[i].maleScore=s[i].maleScore+s[i].c[j].mark[t];
else
s[i].femaleScore=s[i].femaleScore+s[i].c[j].mark[t];
}cout<}
}
cout<<"信息已输入完!
"<}
(3)统计总分函数
voidtongjiScore()
{
cout<<"****统计各个学校总分的结果为:
****"<cout<<"|----------|----------|\n";
cout<<"|学校编号|学校总分|\n";
cout<<"|----------|----------|\n";
for(inti=1;i<=n;i++)
{cout<<"|"<cout<<"|----------|----------|\n";
}
}
(4)按学校编号排序函数
voidsort_schoolNum()//按学校编号输出
{printf("\n\t***按学校编号排序输出***\n");
cout<<"|----------|------------|------------|----------|\n";
cout<<"|学校编号|男团体总分|女团体总分|学校总分|\n";
cout<<"|----------|------------|------------|----------|\n";
for(inti=1;i<=n;i++)
{
cout<<"|"<setw(6)<
cout<<"|----------|------------|------------|----------|\n";
}cout<}
(5)按学校总分排序函数,采用了直接插入排序算法。
(按男团体总分排序函数、按女团体总分排序函数与按总分排序方法差不多,就不贴这两个函数了)
voidsort_score()//按学校总分输出
{
inti,j;
for(i=2;i<=n;i++)
{
s[0].maleScore=s[i].maleScore;
s[0].femaleScore=s[i].femaleScore;
s[0].score=s[i].score;
s[0].schoolNum=s[i].schoolNum;
j=i-1;
while(s[0].score0)
{
s[j+1].maleScore=s[j].maleScore;
s[j+1].femaleScore=s[j].femaleScore;
s[j+1].score=s[j].score;
s[j+1].schoolNum=s[j].schoolNum;
j--;
}
s[j+1].maleScore=s[0].maleScore;
s[j+1].femaleScore=s[0].femaleScore;
s[j+1].score=s[0].score;
s[j+1].schoolNum=s[0].schoolNum;
}
printf("\n\t***按学校总分排序输出***\n");
cout<<"|----------|----------|------------|------------|\n";
cout<<"|学校编号|学校总分|男团体总分|女团体总分|\n";
cout<<"|----------|----------|------------|------------|\n";
for(i=1;i<=n;i++)
{
cout<<"|"<cout<<"|----------|----------|------------|------------|\n";
}cout<}
(6)按学校编号查询学校某个项目情况函数
voidQuery_schoolNum()//按学校编号