生死者游戏终结版数据结构Word文档格式.docx
《生死者游戏终结版数据结构Word文档格式.docx》由会员分享,可在线阅读,更多相关《生死者游戏终结版数据结构Word文档格式.docx(21页珍藏版)》请在冰豆网上搜索。
星期三8:
00分
附:
课程设计报告装订顺序:
封面、任务书、目录、正文、评分、附件(A4大小的图纸及程序清单)。
正文的格式:
一级标题用3号黑体,二级标题用四号宋体加粗,正文用小四号宋体;
行距为22。
正文的内容:
一、课题的主要功能;
二、课题的功能模块的划分(要求画出模块图);
三、主要功能的实现(至少要有一个主要模块的流程图);
四、程序调试;
五、总结;
六、附件(所有程序的源代码,要求对程序写出必要的注释)。
正文总字数要求在5000字以上(不含程序源代码)。
课程设计报告规范
一、需求分析
1、程序的功能。
2、输入输出的要求。
二、概要设计
1、程序由哪些模块组成以及一个模块之间的层次结构、模块的调用关系;
每个模块的功能。
2、课题的总体数据结构和数据库结构;
即要存储什么数据,这些数据是什么样的结构,它们之间有什么关系等。
三、详细设计
1、采用C语言定义相关的数据类型。
2、写出各模块的类C码算法。
3、画出函数的调用关系图。
四、调试分析以及设计体会
1、测试数据:
准备典型的测试数据和测试方案,包括正确的输入及输出结果和含有错误的输入及输出结果。
2、程序调试中遇到的问题以及解决问题的方法。
3、课程设计过程经验教训、心得体会。
五、附录
1、参考书目
2、源程序清单(带注释)
目录
1.系统需求分析1
1.1问题描述1
1.2基本功能1
2.概要设计2
2.1系统总体设计2
2.2.各模块的功能2
2.3相关数据结构设计3
2.4主要算法描述3
2.5主要功能模块流程图:
删除模块4
3.详细设计5
3.1定义结构体类型5
3.2创建链表5
3.3输出函数6
3.4删除函数6
3.5主函数7
3.6函数调用关系图8
4.系统调试9
5.运行结果10
5.1输入界面10
5.2求值界面10
5.3退出程序11
5.4程序调试中的问题11
6.心得体会14
7.附录15
7.1程序源代码15
7.2参考文献17
8.评分表18
1.系统需求分析
1.1问题描述
每N(N>
1.2基本功能
(1)实时显示每扔一个旅客之前,按序号从小到大的顺序显示当前在船上的旅客的编号。
2.概要设计
2.1系统总体设计
本实验设计的目标是运用循环单链表来解决问题,其中运用了许多链表中的基本操作,运用C语言程序编写程序,实现单链表的建立、插入和删除等基本功能,在程序设计成功的基础上,进一步深化理解单链表的作用和实现原理。
程序图如下:
图2.1系统功能模块
2.2各模块的功能
如上图所示,本系统分为四个功能模块分别为:
输入N、K,构建链表,删除函数,输出编号。
下面就每个功能进行详细说明:
(1)输入N、K:
输入N和K,确定船上旅客总人数和报号数,使程序有效正确的运行。
若输入错误,则出现错误提示,再进行重新输入。
(2)构建链表:
初始化单链表后,先创建头结点,再运用尾插法创建一个含有N个结点的循环单链表,使链表具化体;
整个过程在链表中运行,结点在删除时不需要移动大量的结点。
(3)删除函数:
按照规则,报数到K时,则将此结点删除;
删除结点后的链表进行重新连接,又构成了一个新的循环单链表,使得循环继续进行;
(4)输出编号:
实时显示每扔一个旅客之前,按序号从小到大的顺序显示当前在船上的旅客的编号;
同时输出此次是第几个被扔的旅客以及该旅客所在的具体位置。
2.3相关数据结构设计
如果用户的应用程序中设有循环队列,则必须为它设定一个最大队列长度;
若用户无法预估所用队列的最大长度,则宜采用链队列。
本游戏由于N值可改动,所以采用链队列。
n个人围圈,形成线性关系;
处理为逐个删除,故用链式结构合适;
又因为人员围成圆圈,所以此链式结构采用循环方式较好;
排号按照一个方向进行,故数据结构采用带头结点的单向循环链表。
假设人员以首次的编号命名,对每个人员采用编号加以描述。
利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各人的编号。
2.4主要算法描述
该程序的主要算法描述如下:
(1)创建含有N个结点的循环单链表:
while(N>
count)
{if(!
head)创建头结点;
else尾插法创建含有N个结点的循环单链表;
}
p->
next=head;
(尾结点的下一个结点是第一个结点)
returnhead;
(返回头结点地址)
(2)确定被扔下海的旅客编号:
p,q指向链表的第一个结点head,j值初始化,置为1;
while(M>
m/2)//删除一半的结点
{if(K==1)(报号数K等于1时,为特殊情况,需单独处理)
{先输出留在船上所有旅客的编号;
然后按旅客编号的顺序逐个删除;
j自增;
N--;
(N值递减)
直到剩下m/2个。
}
else
{从p指向的结点沿链表前进1步;
计数值count自加1;
if(count==K)(数到K时满足条件,进入if语句)
{先输出留在船上所有旅客的编号;
输出其被扔的顺序号j以及位置p->
number;
删除第k个结点;
计数值count重新设置为1;
N自减1;
else沿着链表继续扫描计数;
(3)输出船上所有剩余的旅客
{按照船上剩余的人数,从头节点开始按顺序逐个输出。
在输出的过程中,每输出二十个就换一行。
2.5主要功能模块流程图:
删除模块
3.详细设计
3.1定义结构体类型
在C语言中,可以定义结构体类型,将多个相关的变量包装成为一个整体使用。
在结构体中的变量,可以是相同、部分相同,或完全不同的数据类型。
这里定义一个GNode结构体,里面包括旅客的编号number,也包括链表的下一个结点的指针。
typedefstructgame
{intnumber;
structgame*next;
}GNode;
3.2创建链表
采用尾插法创建含有N个结点的循环单链表。
循环单链表的建立,若无头结点,则先建立头结点,然后采用尾插法进行新结点的插入;
每插入新的结点,里面的数据也是按结点个数的增加而累加的,即++count;
链表创建完后,需返回头结点地址,即head,以便其他函数调用。
structgame*CreateGame(GNode*head)
{GNode*p=NULL,*q=NULL;
intcount=0;
count)
{if(!
head)
{head=(structgame*)malloc(sizeof(GNode));
head->
number=++count;
p=q=head;
}
else
{p=(structgame*)malloc(sizeof(GNode));
p->
q->
next=p;
q=p;
}
}
p->
}
3.3输出函数
实时输出每扔一个旅客之前,按序号从小到大的顺序显示当前在船上的旅客的编号;
voidrestprint(GNode*head)
{GNode*p=head;
inti;
printf("
留在船上旅客的编号:
"
);
for(i=1;
i<
=N;
i++)
{printf("
%3d"
p->
number);
if(i%20==0)printf("
\n"
p=p->
next;
}
\n\n"
3.4删除函数:
确定被扔下海的旅客编号
首先定义新的两个链表*p,*q,并都指向head头结点;
j值初始化,置为1;
然后按照规则开始循环删除船员,直到只剩下m/2个。
循环过程中,要考虑两种情况:
1、当K=1时,从头结点开始删除,直到剩下m/2个结点,遇到break跳出循环;
2、当K!
=1时,就要报数,当报到K时就扔到海里,同时删除该旅客的结点;
计数值count重新设置为1;
船上剩余总人数N自减1;
沿着链表继续扫描并计数。
voidGameOut(GNode*head,intm)
intcount=1;
intj=1;
q=p=head;
(m/2))
{if(K==1)
{restprint(head);
printf("
第%3d个被扔进海里的位置是:
%3d\n"
j++,p->
head=head->
p=p->
N--;
else
{p=p->
count++;
if(count==K)
%3d\n"
next=p->
count=1;
N--;
3.5主函数
主函数主要是输入船上的总人数N和所要报号数K的值,并进行判断,当不合理时就要重新输入N和K;
接着是创建一个含有N个结点的循环单链表;
调用删除函数,确定被扔下海的旅客编号;
同时输出船上所有剩余旅客的编号。
voidmain()
{structgame*CreateGame(GNode*head);
voidGameOut(GNode*head,intm);
voidrestprint(GNode*head);
GNode*head=NULL;
intm;
printf("
\n请输入船上旅客总人数N:
"
scanf("
%d"
&
m);
N=m;
\n请输入被扔下海旅客的报号数K:
K);
while(K>
N)
{printf("
输入有误!
船上人数值N必须要大于K值:
\n"
请输入船上的人数:
N);
请输入要报的数值K:
head=CreateGame(head);
GameOut(head,m);
3.6函数调用关系图
3.6.1函数调用关系图
3.6.2函数调用关系图说明
运行程序时,先运行主函数,输入N和K的值,然后开始调用创建链表函数,并根据N创建循环单链表,建立循环单链表后,把头指针返回,并赋值给head;
接下来调用删除函数,确定被扔下海的旅客编号,同时调用输出函数,并输出船上所有剩余旅客的编号;
至此整个程序的函数调用和主函数的运行就结束了。
4.系统调试
编写本实验设计程序采用C语言进行,在Visualc++6.0环境下运行。
调试中出现的一些问题:
1、定义结构体类型的指针类型时,需跟结构体保持一致的类型。
刚开始定义时,用了int*next,后面就出现了错误:
cannotconvertfrom'
int*'
to'
structgame*'
(无法从int*型转化成structgame*),改正后该错误消失。
2、函数必须先定义后使用。
写函数时,因为其他函数都是在主函数后面定义的没注意到这个问题,编译时出现了'
CreateGame'
:
undeclaredidentifier,后面通过函数声明解决了这一问题。
3、分号必须是英文半角状态下输入的。
写第一条printf输出语句后,未及时改变输入状态,让在拼音状态下输入分号,编译时出现unknowncharacter'
0xa3'
和missing'
;
'
beforeidentifier'
scanf'
错误。
4、初始化问题。
定义了头结点GNode*head后,未进行初始化,编译时出现警告,链接可以通过,只是在后面输入了N和K的值运行程序的时候,出现应用程序错误(如下图所示)。
经分析可能是由于未进行初始化,导致取值时内存越界。
对头结点指针初始化为空,即GNode*head=NULL后,该错误消失。
5、输出函数的输出时,需考虑输出字符的间隔和换行问题。
最初的程序,由于未考虑到字符间隔,输出的是大数字时,出现了扎堆现象;
而且输出的数字都在一行,不利于观看和检查,因此出于界面友好的要求,加入了换行语句if(i%20==0)printf("
),每输出20个数字后,就会自动跳到下一行,保持界面简介好看。
6、根据函数功能,分类考虑不同的具体情况。
在确定被扔下海的旅客编号的函数中,未考虑到K==1的情况,所以在输入N=20,K=1时,本应该删除编号从1到10的旅客,却出现了其他不符合本程序要求的情况。
7、删除函数运行过程中,总人数N值的变化。
未注意到链表的删除过程中,实际上每一次会删除一个结点,换句话说就是每成功循环一次删除函数,N值都会自减1。
没有N自减语句,则出现死循环。
5.运行结果
5.1输入界面
编译,链接,运行后,出现输入界面,按界面提示输入数据,如下图所示。
5.2求值界面
输入数值N和K后,按Enter键运行,运行结果如下图所示。
5.3退出程序
运行程序后,显示结果正确,根据提示按任意键退出,如下图所示。
5.4程序调试中的问题
5.4.1输入正确的数据:
输入N=20,K=9,能正确运行整个程序,并输出正确的数据。
5.4.2输入异常数据输入:
N=20,K=1时,显示出现错误。
本应该是编号1到10,却变成了另外的情况。
补充:
分析发现删除函数中缺少一种情况,当K=1时,出现错误。
改进后加入if(K==1)的情况,再次运行程序,结果正确,如下图所示
5.4.3输入错误的数据:
N=0,K=9。
所以程序运行后,判断输入有误,提示需要重新输入数据。
6.心得体会
刚知道课题的那天晚上,就已经开始着手做这个课题了,这次课程设计,我们有4个课题,我们组做的是第二个课题:
生死者游戏。
于是马上到网上查找相关资料,并且了解生死者游戏的主要算法。
在经过了一晚上的查阅资料后,有了初步的了解,但对于具体的程序实行过程还是很模糊的。
于是,带着课题中的很多疑问,跟同一小组的同学一起讨论,如果还是不会的话,就找老师寻求解答,李老师也很乐意给我们解疑答惑。
此课题主要采用的是循环单链表进行存取。
在数据结构的选择上,最初犯了一些错误,但后来都纠正了。
最开始想用以前学过的知识C语言描述,就是用数组定义船上的旅客编号,但是遇到一个问题:
不能动态存储要插入的编号。
这样虽然能实现基本功能,但是显得自己可以控制的部分很少。
在后来还认识到,数组不仅不能实现动态存储,而且也存在另一个致命的问题:
输入的数据长度有限。
当达到最大长度的时候,就不能存入数据了,那么整个程序也就瘫痪了。
因此,又再次分析了运行过程的环境:
n个人围成一个圈,形成线性关系,处理的方式是逐个删除,用链式结构合适;
又因为人围成圆圈,所以采用循环方式较好;
报数的时候是按照一个方向进行的,所以数据结构采用带头结点的单向循环链表。
于是,数据结构就选好了。
在考虑用什么算法上,也花了一定的时间。
在分析好了整个过程之后,就开始选择算法了,开始我在脑中搜索,寻找有没有以前学过的相似或者相同的算法,终于想到了一个:
与素数的判断算法有相同之处。
记得素数的判断是通过改变标记来实现的,这个课题也是可以通过改变标记实现:
先把船上的所有旅客标记号,都赋初值1,然后遇到要扔下海的编号时,就改变标记,变为0,最后输出函数的时候,只要输出标记号为1的旅客的编号就行了。
考虑到这点之后,又马上开始了程序的修改,这样算法就基本上确定了。
在程序的设计中,数据结构的选择是基本的考虑因素。
数据结构的优劣在一定程度上决定论系统功能实现的难易和系统质量的高低。
很多时候,数据结构选好了,那么相应的算法也就可以确定了:
有些时候也会反过来,需要先确定算法,再确定数据结构。
在做这个课题的过程中,学到了很多东西,学会了怎么整合资源,怎么在合作中共同进步,这整个过程本身就非常有意思,同时也觉得这种实践式的学习是一种更有效的学习方式。
7.附录
7.1程序源代码(注释版)
#include<
stdio.h>
malloc.h>
intN,K;
typedefstructgame//定义结构体类型
//函数声明
N=m;
{printf("
}
GameOut(head,m);
structgame*CreateGame(GNode*head)//创建循环单链表
{if(!
{head=(structgame*)malloc(sizeof(GNode));
p=q=head;
{p=(structgame*)malloc(sizeof(GNode));
p->
}
voidrestprint(GNode*head)//输出扔旅客下海之前的旅客编号
{GNode*p=head;
if(i%20==0)printf("
voidGameOut(GNode*head,intm)//确定被扔下海的旅客编号
intj=1;
{if(K==1)
else
{p=p->
count++;
if(count==K)
N--;
elseq=p;
7.2参考文献
[1]谭浩强、张基温编著《C语言程序设计教程》(第3版).北京:
高等教育出版社,2006年
[2]李春葆等.《数据结构教程》(第3版).北京:
清华大学出版社.2009年
[3]李春葆等.《数据结构教程(第3版)上机实验指导》.北京:
[4]网上相关资料
8.评分表
计算机与通信学院课程设计评