基于单向循环链表的约瑟夫Joseph环设计解读.docx
- 文档编号:25081716
- 上传时间:2023-06-04
- 格式:DOCX
- 页数:14
- 大小:216.83KB
基于单向循环链表的约瑟夫Joseph环设计解读.docx
《基于单向循环链表的约瑟夫Joseph环设计解读.docx》由会员分享,可在线阅读,更多相关《基于单向循环链表的约瑟夫Joseph环设计解读.docx(14页珍藏版)》请在冰豆网上搜索。
基于单向循环链表的约瑟夫Joseph环设计解读
长春建筑学院《数据结构》课程设计(论文)
基于单向循环链表的约瑟夫(Joseph)环设计
Basedonone-waycircularlinkedlistofJoseph(Joseph)ringdesign
年级:
学号:
姓名:
专业:
指导老师:
二零一三年十二月
摘要
约瑟夫问题是由古罗马著名的史学家Josephus提出的问题演变而来,所以通常称为Josephus问题。
改进约瑟夫问题的描述是:
编号为1,2,…,n的n个人按顺时针方向围坐一,每人有一个密码Ki(整数),留作其出圈后应报到Ki后出圈。
报数方法采用顺时针报数和逆时针报数交替进行,初始密码可任意确定。
求最后剩下的人的编号。
这个就是约瑟夫环问题的实际场景,后来老师要求我们对要求中的每人所持有的密码以及第一次的报数上限值要用随机数产生。
因此约瑟夫环问题如果采用双向循环链表则能很好的解决。
循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。
p->link=head解决问题的核心步骤:
先建立一个具有n个链结点,无头结点的循环链表,然后确定第一个报数人的位置,并不断地从链表中删除链结点,直到链表为空。
关键词:
约瑟夫环;双向循环链表;数据结构;删除结点
Abstract
JosephproblemisputforwardbyfamousancientRomanhistorianJosephusproblemhasevolved,sooftenreferredtoasJosephusproblem.ImprovedJosephadescriptionoftheproblemis:
Numbersfor1,2,...,nnindividualssittingaroundaclockwisecircle,
EachwithapasswordKi(integer),reservedfortheoneswithreportshouldKiafterones.Countoffmethodthenumberoffclockwiseandcounterclockwisecountoffalternates,initialpasswordcanbearbitrary.Finallytheserialnumberoftherestofthepeople.ThisistheactualsceneofJosephringproblem,thentheteacheraskedustorequesteachheldbythepasswordandthelimitonthenumberoffofthefirsttimetouserandomnumberisgenerated.SoJosephringproblemifthebidirectionalcircularlinkedlistcanbeaverygoodsolution.Circularlinkedlistdatastructureisalistofthetailelementpointertothefirstelement.P->link=headthecorestepstosolvetheproblem:
first,setupachainofnnodes,theheadlessnodesofcircularlinkedlist,andthendeterminethepositionofthefirstpersontocountoff,andconstantlytodeletechainnodefromthelist,untilthelistisempty.
Keywords:
Josephring;Thebidirectionalcircularlinkedlist;Datastructure;Deletenodes
第1章绪论
引言:
本次选做的课程设计是改进约瑟夫(Joseph)环问题。
约瑟夫环问题是一个古老的数学问题,本次课题要求用程序语言的方式解决数学问题。
此问题仅使用单循环链表就可以解决此问题。
而改进的约瑟夫问题通过运用双向循环链表,同样也能方便地解决。
1.1设计目的:
1、掌握单向循环链表的建立。
2、掌握单向循环链表的操作。
1.2设计内容
编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个仍开始顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。
请设计一个程序求出出列顺序。
1.3设计要求
1、利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。
2、测试数据:
m的初值为20,n=7,7个人的密码依次为3,1,7,2,4,7,4,首先m=6,则正确的输出是什么?
3、输入数据:
建立输入函数处理输入的数据,输入m的初值n,输入每个人的密码,建立单向循环链表。
4、输出形式:
建立一个输出函数,将正确的出列顺序输出。
1.4设计思想
利用单循环链表解决本问题,先创建一个有n个的单循环链表,依次录入密码。
然后从第一个结点出发,连续略过 m-1个结点,将第m个结点从链表中删除,并将第m个结点的密码作为新的么值,接着从下个结点开始,循环此过程,直至链表为空。
第2章系统总体设计
2.1基本理论
在建立双向循环链表时,因为约瑟夫环的大小由输入决定。
为方便操作,我们将每个结点的数据域的值定为生成结点时的顺序号和每个人持有的密码。
进行操作时,用一个指针current指向当前的结点,指针front始终指向头结点。
然后建立双向循环链表,因为每个人的密码是通过rand()函数随机生成的,所以指定第一个人的顺序号,找到结点,不断地从链表中删除链结点,直到链表剩下最后一个结点,通过一系列的循环就可以解决改进约瑟夫环问题。
2.2概要设计
已知n个人(以编号1,2,3...n分别表示)围成一圈。
从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到一圈的人全部出列。
这个就是约瑟夫环问题的实际场景,有一种是要通过输入n,m,k三个正整数,来求出列的序列。
这个问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。
p->link=head。
解决问题的核心步骤:
首先建立一个具有n个链结点,无头结点的循环链表。
然后确定第1个报数人的位置。
最后不断地从链表中删除链结点,直到链表为空。
改进的约瑟夫环问题与原问题思路一致,只是不再采用单循环链表存储结构,而采用双向循环链表,而且用一个判断语句来决定报数的方向的顺时针还是逆时针。
本课程设计主要采用了类的数据结构,程序中包含了两个类:
Linklist , Joseph。
2.3类LinkList
主要功能是创建结点,每个结点数值域包括data,password,还有指示前驱结点的指针llink,和指示后继结点的指针rlink。
2.4类Joseph
主要功能是实现创建双向循环链表及一些相应的操作。
2.5类异常处理
在C++程序中,可以使用try-throw-catch结构处理程序异常。
采用这一程序结构能够将使用和实现分离:
类和函数的实现者使用throw语句易地错误类别通知使用者。
使用者根据获悉的错误类别采取相应的措施,这就是异常处理
第3章详细设计
改进约瑟夫环问题的基本思路和原问题基本一致,只是一个采用单循环链表,另一个采用双向循环链表来解决问题。
第一步是定义结构变量结点linklist,并在该结点下定义结点的元素域:
data,password,指针域:
lLink和rLink。
然后建立一个由n个链结点,无表头结点的双向循环链表。
并由构造函数对结点赋值,由随机函数rand()产生每个结点的password。
由于每个结点的password是由随机函数产生的,也就是每个结点的password是后知的,所以在一开始人为地指定一个结点的顺序,由此结点开始报数。
报password个数后,报到的那个结点被删除,它的password被记录下,由它的下一个结点开始逆方向报数………如此循环,直到循环链表里只剩下一个结点,那就是问题所求的结果。
具体到问题上,还需要创建一个Joseph类,由构造函数来初始化,输入所有的人数,也就是表长,然后指定由第几个人开始报数。
在Joseph类中定义一个GetWinner()函数,由它来实现获得最后的胜利者。
并在该类中设置一个判断语句来确定先由顺时针报数并淘汰了一个人之后,再按逆时针顺序报数,如此交替进行。
3.1创建结点Node
链表都是由一个个结点组成,由于结点的不同,组成的链表也不同。
因此需要创建双向链表结点。
由于每一个结点有一个密码和一个序号,所以可以将结点结构体定义为:
struct Node{
rLink
password
data
llink
int data; int password; DNode* llink;
DNode* rlink;}
3.2创建双向循环链表
创建一个空双向循环链表,双向循环链表和每个结点包括三个域:
Element, lLink,rLink.其中element为元素域,rLink域为指向后继结点的指针,新增的lLink域用以指向前驱结点。
双向链表也可以带表头结点,并且也可以构成双向循环链表。
此时,表头结点的rLink,lLink分别指向双向循环链表的头结点(或表头结点)和尾结点。
一个结点的lLink域的指针指向它左边结点的后部,这并不意味着该结点的lLink域保存的仍是该左边结点存储块的起始地址。
在此处,指针指向某个结点任何部分都是等价的,都是指该存储块的起始位置。
每当结点计数到某一结点时,将他的前驱结点接到他的后继结点,然后将他的密码值password赋给计数变量,再将此结点删除。
如此循环下去,直到最后变为空的单循环链表为止。
由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍然是围成一个圆圈的,可以使用循环表,由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。
所以,对于所有人围成的圆圈所对应的数据结构采用一个不带头结点的循环链表来描述。
设头指针为front,front始终指向头结点,并定义指针current记录当前的结点。
并根据具体情况移动(顺逆时针)。
为了记录退出的人的先后顺序,采用一个顺序表进行存储。
程序结束后再输出依次退出的人的编号顺序。
由于只记录各个结点的data值就可以。
最后通过函数调用来输出顺序。
要解决约瑟夫环问题,首先一点就是必须有一个环,所以第一步我们必须建立一个双向循环链表。
而建立一个双向循环链表必须有一个空的双向循环链表,然后运用尾插法建立一个双向循环链表,这样约瑟夫环就创建出来了,接下来就是处理约瑟夫环问题。
3.3从链表中删除结点
在双向循环链表中,一个结点的前驱结点地址保存在该结点的lLink域中,这样可以方便地实现在一个指定结点之前插入一个新结点的操作,也可以方便地删除某个指定结点。
函数通过代码:
q->llink->rlink=q->rlink;q->rlink->llink=q->llink;delete q; 来删除当前的那个结点q,通过循环来一次次删除当前的结点,直到链表中剩下最后一个结点。
第四章流程分析图
4.1函数生成过程
此部分为createlist函数。
首先初始化变量,再输出提示性语句,等待用户输入数据,将总人数和初始上限值分别存入num和m。
以num为上限值建立单循环链表,最后返回L。
此部分为printlist函数部分。
定义变量temp=m,从第一个人开始进行报数,指针q和p指向第一个人L,当q->next=p时,q=q->next;否则当q->next!
=q时—temp,直到—temp!
=0时输出p所指向的节点的num;重复以上处理直到q->next!
=q为假时结束该函数。
4.2主要功能模块设计
此部分为主程序部分。
分别调用函数createlist和printlist,所有人输出,程序结束。
并通过while循环对程序进行重复使用
4.3函数主要调用关系图
第5章系统测试
5.1调试分析
这次的课程设计的代码很冗长,所以等有了解题思路后,把代码都写上后难免会有很多错误。
当第一次把整个程序写好后运行,出现了很多错误。
不过经过一点点的改正,错误也慢慢地变少。
这也说明做事要认真,尤其做计算机这方面工作的时候,因为计算机不容许不一点点的错误,有了一点小错误和有一个大错误在计算机看来都是一样的,都不会得不到结果。
有些小错误,比如说少了个分号,变量忘了定义,数据溢出等都是些小错误,但也不能松懈。
因为要注意的地方很多,经过多次尝试,问题也就自然而然的解决了,而且以后遇到这方面的问题都会觉得比较得心应手。
在随机设置每个结点的password时也曾是个问题,因为我做的随机函数一直都用不好,要不是每次随到的都是一样的,要么就是每次随到的数都很大,后来通过老师的耐心讲解才得以解决。
在调试的过程中,类的优势很明显,能很简单的把问题解决,而不需要使用的其他的一些比较复杂的方法。
5.2实验结果
生成界面如图4.1,4.2所示:
结果分析:
当程序运行的时候会出现如上图所示的提示,要求使用者输入程序中所需的输入总人数,使用者只需输入自己所想的总人数,系统便会随机产生每个人对应的密码,同时随机产生第一次的报数上限值。
最后系统会给出出列的次序,最后产生的编号便是此次游戏的获胜者。
使用者还可按下任意键,进行下一次的游戏。
结论
为期一周的课程设计快结束了,通过这次数据结构课程设计,我感受最深的就是对于循环链表的使用,可以说对循环链表有了比以前更进一步的认识,以前只是一知半解的,如果只给个题目自己根本不能把程序完整地编写出来,所以这次课程设计最大的收获就在于对循环链表有了一定的理解,包括其中的一系列操作,如建立一个循环链表,删除链表中的一个结点,增加一个结点等。
在这次课程设计过程中需要我们一边设计一边探索,这这个过程当中我发现自己在数据结构方面知识掌握不够深入,对一些基本概念不能很好的理解,对一些数据结构不能够熟练的进行上机实现,这是自己比较薄弱的。
学好基础知识是理论付诸实践的前提,这样理论和实践才能充分地结合起来。
在以后的学习中,我还要努力改正,充分利用上机实验的机会提高自己。
在程序的输入的时候,因为自己对键盘的不熟练,代码又很多很繁琐,常常会产生放弃的念头,从中我也感受到只有坚持到底,胜利才会出现。
在调试程序的时候我也有所体会,虽然约瑟夫环问题不是很难,但调试的时候还是会出现很多错误,因此我们不能认为容易就不认真对待。
在以后的学习中,要能不断发现问题,提出问题,解决问题,从不足之处出发,在不断学习中提高自己。
致谢
感谢我的指导老师常大俊老师的辛勤知道和不厌其烦的解释和悉心的指导,感谢学校为我们提供这次课程设计的机会,让我们可以锻炼自己的能力,提高对计算机专业课的认识。
还要感谢同组的同学的帮助,使我们一起完成这个课程设计。
这次课程设计是我在专业课的学习中宝贵的经验。
参考文献
[1]唐国民,王国钧.《数据结构》.第一版.清华大学出版社,2009年
[2]郑山红,李万龙,于秀霞.《C语言程序设计》.第二版.人民邮电出版社,2012年.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 单向 循环 约瑟夫 Joseph 设计 解读