约瑟夫环问题课程设计说明书.doc
《约瑟夫环问题课程设计说明书.doc》由会员分享,可在线阅读,更多相关《约瑟夫环问题课程设计说明书.doc(33页珍藏版)》请在沃文网上搜索。
1、 目录: 摘 要2前言3课程设计报告正文4一需求分析4二概要设计5三详细设计71各模块关键代码及算法的解释:72函数的调用关系图10四调试分析13五用户使用说明15六测试结果16七源程序(带注释)22总结26参考文献26致谢28附录,带注释的源程序29摘 要当约瑟夫环中某人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍然是围成一个圆圈的,可以使用循环表,由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。所以,对于所有人围成的圆圈所对应的数据结构采用一个不带头结点
2、的循环链表来描述。设头指针为p,并根据具体情况移动。为了记录退出的人的先后顺序,采用一个顺序表进行存储。程序结束后再输出依次退出的人的编号顺序。由于只记录各个结点的number值就可以,所以定义一个整型一维数组。如:int quitn;n为一个根据实际问题定义的一个足够大的整数。 解决问题的核心步骤: 1.建立一个具有n个链结点,无头结点的循环链表 2.确定第1个报数人的位置 3.不断地从链表中删除链结点,直到链表为空前言约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元6670年犹太人反抗罗马的起义。约瑟夫作为一个将军,设法守住了裘达伯特城
3、达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难。在那里,这些叛乱者表决说“要投降毋宁死”。于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的。约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品一起投降了罗马。 约瑟夫环问题的具体描述是:设有编号为1,2,n的n(n0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。课程设计报告正文一需求分析1输入的形式和输入值
4、的范围本程序中,输入人数n(n小于等于30)和初始密码m(m大于等于1),然后给每个人输入所持有的密码key,均限定为正整数。用单循环链表模拟约瑟夫环,从队头开始从1报数,报到m的人出列,再把此人的密码赋给m,继续下一轮的报数,直到所有的人出列。结果出来后再选择输入一数字,输入1继续新一轮的游戏,输入0结束,退出此游戏。演示程序以用户和计算机对话方式进行,根据提示信息由用户从键盘输入数据,输入的形式为一个以“回车符”为结束标志的正整数。2输出的形式在计算机终端上显示提示信息之后,有用户在键盘上输入演示程序中规定的运算命令,相应的输入数据和运算结果显示在其后。运行后输出的结果是约瑟夫环的相关信息
5、和经过报数后出队的人的序列号及相关信息。程序执行的命令包括:(1)输入人数和初始密码 (2)输入所有人的密码 (3)显示输入的所有人的编号及相应的密码(4)输出出列密码及编号 (5)结束 即:(1)构造单循环链表;(2)输出循环链表的信息;(3)按照出列的顺序输出各人的编号3程序功能 提供用户从键盘输入,Joseph约瑟夫环的必要数据,并从屏幕显示出列顺序。4测试数据(1)n=7 ,m=20(常规数据), 7个人的密码依次为3,1,7,2,4,8,4,正确的输出序列为6,1,4,7,2,3,5.(2)n=5,m=6(常规数据),5个人的密码依次为2,5,4,6,7,正确的输出序列为1,3,4,
6、2,5。(3)n=31, m=3(错误数据),“这个人数太大了,请重新输入”。(4)n=0, m=3(错误数据),“这个约瑟夫环里没有人!”。(5)n=1, m=4,(边缘数据),正确的输出序列为1。(6)n=3, m=1,(边缘数据),正确的输出序列为1,3,2。第一组为常规数据,中间两组为错误数据,后面两组为边缘数据。5设计思路及方案用单循环链表来模拟约瑟夫环,结点信息包括编号、密码、指向下一个结点的指针,用三大主要的函数来实现功能,包括创建链表的函数、输出链表信息的函数、删除结点也就是出队的函数、主函数等函数。二概要设计1抽象数据类型的定义为实现上述功能,应以有序单向循环链表表示约瑟夫环
7、。为此,需要有一个抽象数据类型。该抽象数据类型的定义为:ADT LinkList数据对象:D= ai | ai termset,i=1,2,n,n=0,termset中每个元素包含编号,密码,和一个指向下一节点的指针数据关系:R1= | ai-1, ai D , i=2,n基本操作:LinkList EvaluList(int n);/对单向循环链表进行尾插入赋值int size(LinkList L);/求链表的节点个数Status ScanList(LinkList L);/遍历单向循环链表Status Joseph(LinkList &L,int m);/约瑟夫环的实现此抽象数据类型中的
8、一些常量如下:#define TRUE 1#define FALSE 0#define OK 1typedef int Status;typedef double ElemType;单向循环链表中节点的定义如下所示:typedef struct LNodeint number;int data;struct LNode *next;LNode, *LinkList;2主程序的流程void main() 初始化; 输入数据; 执行功能;显示结果;3模块的设计及介绍(1)主程序模块 Void main()初始化;do 接受命令;处理命令;while(“命令”=“退出”);(2)创建链表模块 Sta
9、tic void creatlist(行参)初始化;For接受命令;处理命令 (3)输出链表信息模块static void PrntList(参数)定义变量并初始化;输出命令; (4)删除结点也就是出队模块static void StatGame(参数)定义变量并初始化; While 开始报数; 输出结果;4各程序模块之间的层次(调用)关系。本程序包含以下模块:(1)主程序模块:(2)各功能模块实现顺序表的各项功能。各模块的调用关系:主程序 各功能模块三详细设计1各模块关键代码及算法的解释:(1) 主函数模块代码circularlist pHead=NULL;int main(void) in
10、t n, m, iflag=1while(iflag=1)printf(请输入总人数n=); scanf(%d,&n); printf(n再请输入初始报数上限m=); scanf(%d,&m); CreatList(&pHead,n); printf(n输出所有人的信息如下:n);PrntList(pHead); printf(n按照出列顺序输出每个人的编号:n); StatGame(&pHead, m); printf(n约瑟夫环的游戏完成!n); printf(输入1开始建环做游戏,输入0退出该游戏,请选择!);scanf(%d,&i); return 0;程序解释:该主函数用一个循环语句
11、,来执行其它的函数的功能。从键盘输入总人数和初始的报数上限,再调用创建链表的函数建环,后输出单循环链表的信息,再调用StatGame()函数,报到上限的那个结点从表中删除既出队,然后再选择输入一个数确定是否继续游戏,输入1继续,输入0退出。(2) 创建单循环链表函数模块代码static void CreatList(circularlist * ppHead, const int n) int i,ikey; Node *pNew, *pCur; for(i=1;inext=*ppHead; else pNew-next=pCur-next; pCur-next=pNew; pCur=pNew
12、; 程序解释:用一个for循环来给链表的每个结点分配空间,并从键盘输入每人所持有的密码,如果头结点的值为空,使其指向新生成的一个结点,新结点的next指针指向头结点,如果不是,则当前结点的next的值赋给新结点的next,然后当前结点的next值指向新结点,再当前结点的指针指向新结点,实现链表的建立。(3)删除结点函数代码static void StatGame(circularlist * ppHead, int ikey) int iCounter, iFlag=1; Node *pPrv, *pCur, *pDel; pPrv=pCur=*ppHead; while(iFlag) ! *
13、/ for(iCounter=1;iCounternext; if(pPrv=pCur) iFlag=0; pDel=pCur; Prv-next=pCur-next; pCur=pCur-next; ikey=pDel-key; printf(第 %d个人出列, 所持有密码是: %dn, pDel-id,pDel-key); free(pDel); ppHead=NULL; 程序解释:设立一个标签,值为1执行循环语句,值为0跳出循环。循环语句里的for循环实现报数功能,也就是结点移动的功能,移动ikey个结点,再删除第ikey个结点,并把该结点的密码值赋给ikey,再从该结点的下一个结点移动
14、,重复上面的过程,结点全都删除后使标签的值为0,结束while循环,游戏结束。开始2函数的调用关系图定义各种变量2.1主程序流程图输出界面假输入参与人数和密码判断是否满足人数上限结束假a=1?真while语句输出密码输出出列顺序调用PrntList ();开始进行约瑟夫环的操作初始化单链表调用CreaList ();构造单链表真2.2创建单循环链表函数流程图开始i=n?输入每人所持有的密码创建结点结束是否2.3删除结点函数(出队函数)程序流程图iflag=1icounter=ikey从1开始报数,报m结束报m的人出列prv=pru开始真真假假假真iflag=0结束2.4子程序流程图假retur
15、n TRUEif(!pHead)真输入一数值引用指针*pHeadEmptyList()return FALSE四调试分析1.调试过程中遇到的问题及解决方法及对设计与实现的回顾讨论和分析程序的编写和调试基本正常。遇到的问题有:指针的指向的边界问题。当执行输入人数时,输入0程序出现了意想不到的错误,所以再重新设计时加入了对空节点的处理。在链表节点的设计上,最初是仅包含密码和指针,但是后来考虑到链表节点删除时会带来一系列的编号变化,编号难以确定,所以节点设计上又加了一个编号。在单向链表的赋值操作时,原本是以一个不变的L作为头结点,但是这种赋值方法带来了诸多变量设计的问题,所以将L为节点,赋值完成后,
16、再让L指向头结点。程序原本是没有求节点个数的函数,但是在约瑟夫环的实现函数中,节点的个数时时影响着结果的判断,所以加入了该函数。2.算法的时空分析在空间复杂度方面第一种算法可以增加一存储出列序列的数据组,需要辅助空间,而且与问题的规模Maxsize有关。第二种算法也可直接对约瑟夫环进行求解,结果仍然存储在环中,好处是没有增加额外的空间。在时间复杂度方面,第一种算法可以从中可以看到,报数m的时间极短,问题在出列时,由于用顺序表做删除操作,平均移动大约表中一半的元素,影响效率.但是,两者都存在二重循环,算法中语句重复执行次数的数量级没有发生变化,即时间复杂度O相同。与这两种算法不同的是,动态链表实
- 1.请仔细阅读文档,确保文档完整性,对于不预览、不比对内容而直接下载带来的问题本站不予受理。
- 2.下载的文档,不会出现我们的网址水印。
- 3、该文档所得收入(下载+内容+预览)归上传者、原创作者;如果您是本文档原作者,请点此认领!既往收益都归您。
下载文档到电脑,查找使用更方便
20 积分
下载 | 加入VIP,下载更划算! |
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 约瑟夫 问题 课程设计 说明书
