单向循环链表和双向循环链表,跟普通的非循环链表的区别,主要是还是在于add和remove方法,这次事件解决下,用双向循环链表的思路解决约瑟夫问题。
(一)约瑟夫问题的解决①介绍
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。问题分析与算法设计约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。这里给出一种实现方法。题目中30个人围成一圈,因而启发我们用一个循环的链来表示,可以使用结构数组来构成一个循环链。结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该人是否被扔下海的标记,为1表示还在船上。从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。这样循环计数直到有15个人被扔下海为止。
②分析思路
借助循环链表非常的好做,这不是一个环吗?可以考虑增设1个成员变量,3个方法。
current:用于指向某个节点
voidreset():让current指向头结点first
Enext():让current往后走一步,也就是current=current.next
Eremove():删除current指向的节点,删除成功后让current指向下一个节点。
③增加成员变量
④next
⑤reset
⑥remove
直接节点删除,设置成私有的,就是传过去节点直接删除。删除之前需要先拿到它的下一个,就可以放心删除了。特殊情况需要考虑:current需要指向它的下一个。当只剩余一个节点的时候,如果size==0的时候直接current等于null就可以了。
⑦测试类(二)静态链表①介绍
前面锁学习的链表,是依赖于指针(引用)实现的。早期的编程语言是没有指针的,比如早期的BASIC,FORTRAN语言。没有指针的情况。
②实现链表
1.可以通过数组来模拟链表,称为静态链表。2.数组的每个元素存放2个数组:值、下个元素的索引。3.数组0位置存放的是头结点信息。4.索引没有负数,如果是负数就是结束。
思考:如果数组的每个元素只能存放一个数据呢?只能搞2个数组,一个数组UC南方索引关系,一个数组存放值。
PS:约瑟夫问题不管是输到几删,不用循环列表也可以,也可以直接数组就行。代码也比较好理解。