约瑟夫环问题讲解
约 瑟 夫 环 问 题 的 三 种 解 法

约瑟夫环的普通解法及优化约瑟夫环问题的普通解法很简单,就是不断遍历循环链表,删除节点,假如有n个人,等到第m个人报数时杀掉这个人,即删除这个节点,直到只剩下一个人。
struct NodeNode(int data):_data(data),_pNext(NULL)int _data;Node* _pNext;1,普通解法,时间复杂度为O(n*m),因为删掉一个节点需要遍历 m 次;代码实现Node* josephuskill1(Node* pHead,int m)--第m个人被杀掉if(pHead == NULL)return NULL;Node* pCur = pHead;while(pCur-_pNext)pCur = pCur-_pNext;pCur-_pNext = pHead;pCur = pHead;int num = m;Node* pRev;while(pCur-_pNext != pCur)--只剩下一个节点 while(--num)pRev = pCur;pCur = pCur-_pNext;pRev-_pNext = pCur-_pNext;--删除节点pHead = pCur;return pHead;测试代码void funtest1()Node node1(1);Node node2(2);Node node3(3);Node node4(4);Node node5(5);node1._pNext = node2;node2._pNext = node3;node3._pNext = node4;node4._pNext = node5;Node* ret = josephuskill1(node1,3);int main()funtest1();getchar();return 0;2.约瑟夫环的优化,时间复杂度为O(n)思路:我们直接直到最后存活的节点,然后删除其余节点,保存这个节点;问题是:我们怎样直接找到该节点呢?代码实现:int GetLive(int i,int m)--i是链表中总的节点个数,m是第m个报数的人被杀掉,返回存活的新的编号if(i == 1)--当链表中只剩下一个节点的时候,此时该节点对应的新编号就是1return 1;return (GetLive(i-1,m)+m-1)%i+1;--递归,当i=2时,我们得到存活节点(i=2)对应两个节点时的编号,直到i = N 时Node* josephuskill2(Node* pHead,int m)--第m个人被杀掉if(pHead == NULL)return NULL;Node* pCur = pHead;while(pCur-_pNext)pCur = pCur-_pNext;pCur-_pNext = pHead;int num = 1;pCur = pHead;while(pCur-_pNext != pHead)num++;--获取链表中节点的个数pCur = pCur-_pNext;int retnum = GetLive(num,m);--得到的retnum就是存活节点在总数为num个节点的编号--根据编号找到节点while(--retnum)pHead = pHead-_pNext;pHead-_pNext = pHead;return pHead;测试代码:void funtest1()Node node1(1);Node node2(2);Node node3(3);Node node4(4);Node node5(5);node1._pNext = node2;node2._pNext = node3;node3._pNext = node4;node4._pNext = node5;Node* ret = josephuskill2(node1,3);int main()funtest1();getchar();return 0;18 3、数到某个数(如:M)的时候,此人出列,下一个人重新报数结果表明,第一种循环链表的方式比第二种取模运算的方式要快,由于比例不是线性的,不能说是几倍,而且这个测试和python内部实现有关,换作C语言O3优化后结果就不一定一样了,所以测试结果不能说明什么哈~k k+1 k+2 . n-2, n-1, 0, 1, 2, . k-2f(N?1,M)表示,N-1个人报数,每报到M时杀掉那个人,最终胜利者的编号int cycle0(int n, int m){ -- 使用链表实现-- 若第 i 个人存活,则 men[i] == 0,否则 men[i] == 死亡序号CircularList CL=new CircularList();for (int i = 1; i = total; i++)循环语句do { g++; } while( g = N ) 可以用 for( ; g = N ; g++ ) {? }代替。
约 瑟 夫 环 问 题 的 三 种 解 法

约瑟夫环问题python解法约瑟夫环问题:已知n个人(以编号1,2,3.n分别表示)围坐在一张圆桌周围。
从编号为k的人开始报数,数到k的那个人被杀掉;他的下一个人又从1开始报数,数到k的那个人又被杀掉;依此规律重复下去,直到圆桌周围的人只剩最后一个。
思路是:当k是1的时候,存活的是最后一个人,当k=2的时候,构造一个n个元素的循环链表,然后依次杀掉第k个人,留下的最后一个是可以存活的人。
代码如下:class Node():def __init__(self,value,next=None):self.value=valueself.next=nextdef createLink(n):return Falseif n==1:return Node(1)root=Node(1)tmp=rootfor i in range(2,n+1):tmp.next=Node(i)tmp=tmp.nexttmp.next=rootreturn rootdef showLink(root):tmp=rootwhile True:print(tmp.value)tmp=tmp.nextif tmp==None or tmp==root: def josephus(n,k):if k==1:print('survive:',n)root=createLink(n)tmp=rootwhile True:for i in range(k-2):tmp=tmp.nextprint('kill:',tmp.next.value) tmp.next=tmp.next.nexttmp=tmp.nextif tmp.next==tmp:print('survive:',tmp.value)if __name__=='__main__':print('-----------------')josephus(10,2)print('-----------------')josephus(10,1)print('-----------------')输出结果如下:-------------------------------------分界线-----------------------------------------感谢大家建议,第一种方法是直观暴力裸搞,确实不太简洁,下面写出我的第二种方法,求模来搞起,代码少了一些,如下:def josephus(n,k):if k==1:print('survive:',n)people=list(range(1,n+1))while True:if len(people)==1:p=(p+(k-1))%len(people)print('kill:',people[p])del people[p]print('survive:',people[0])if __name__=='__main__':josephus(10,2)josephus(10,1)运行结果和上面一样。
经典问题约瑟夫环讲解

1.需求分析以无歧义的陈述说明程序设计的任务,强调的是程序要做什么?并明确规定:(1) 输入的形式和输入值的范围;输入的值为数字(2) 输出的形式;输出的形式为一串数字如:6,1,4,7,2,3,5(3) 程序所能达到的功能;编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。
(4) 测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果。
输入错误时一般不会显示结果。
总体归纳为:1.约瑟夫环(Joseph)问题的一种描述是:编号为1,2……,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。
2.演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,有用户在键盘上输入演示程序中规定的运算命令,相应的输入数据和运算结果显示在其后。
3.程序执行的命令包括:1)输入初始密码和人数 2)输入所有人的密码 3)显示输入的所有人的编号及相应的密码4)输出出列密码及编号 5)结束4.测试数据(1)m=20, n=7, 7个人的密码依次为3,1,7,2,4,8,4(2)m=7,n=20,20个人的密码依次为3,1,7,2,4,8,4(2)组数据为错误数据测程序的健壮性。
2.概要设计说明本程序中用到的所有抽象数据类型的定义、主程序的流程以及各程序模块之间的层次(调用)关系。
ADT LinearList{数据元素:D={ai| ai∈D0, i=1,2,…,n n≥0 ,D0为某一数据对象}关系:S={<ai,ai+1> | ai, ai+1∈D0,i=1,2, …,n-1}该程序只有主程序。
约瑟夫环问题

约瑟夫环问题问题描述:有n个⼈,编号分别从0到n-1排列,这n个⼈围成⼀圈,现在从编号为0的⼈开始报数,当报到数字m的⼈,离开圈⼦,然后接着下⼀个⼈从0开始报数,依次类推,问最后只剩下⼀个⼈时,编号是多少?分析:这就是著名的约瑟夫环问题,关于来历不再说明,这⾥直接分析解法。
解法⼀:蛮⼒法。
我曾将在⼤⼀学c语⾔的时候,⽤蛮⼒法实现过,就是采⽤标记变量的⽅法即可。
解法⼀:循环链表法。
从问题的本质⼊⼿,既然是围成⼀个圈,并且要删除节点,显然符合循环链表的数据结构,因此可以采⽤循环链表实现。
解法三:递推法。
这是⼀种创新的解法,采⽤数学建模的⽅法去做。
具体如下:⾸先定义⼀个关于n和m的⽅程f(n,m),表⽰每次在n个编号0,1,...,n-1中每次删除的报数为m后剩下的数字,在这n个数字中,第⼀个被删除的数字是(m-1)%n,为了简单,把(m-1)%n记作k,那么删除k之后剩下的数字为0,1,2,...,k-1,k+1,...,n-1并且下⼀次删除的数字从k+1开始计数,这就相当于剩下的序列中k+1排在最前⾯,进⽽形成k+1,..,n-1,0,1,2,...,k-1这样的序列,这个序列最后剩下的数字应该和原序列相同,由于我们改变了次序,不能简单的记作f(n-1,m),我们可以记作g(n-1,m),那么就会有f(n,m)=g(n-1,m).下⼀步,我们把这n-2个数字的序列k+1,..,n-1,0,1,2,...,k-1做⼀个映射,映射的结果是形成⼀个从0到n-2的序列。
k+1对0,k+2对1,......,n-1对n-k-2,0对n-k-1,1对n-k,....,k-1对n-2这样我们可以把这个映射定义为p,则p(x)=(x-k-1)%n,它表⽰如果映射前的数字是x,映射后为(x-k-1)%n,从⽽这个映射的反映射问为p-1(x)=(x+k+1)%n由于映射之后的序列和原始序列具有相同的形式,都是从0开始的序列,所以可以⽤函数f来表⽰,即为f(n-1,m),根据映射规则有:g(n-1,m)=p-1[f(n-n,m)]=[f(n-1,m)+k+1]%n,最后把之前的k=(m-1)%n带⼊式⼦就会有f(n,m)=g(n-1,m)=[f(n-1,m)+m]%n.这样我们就可以得出⼀个递推公式,当n=1时,f(n,m)=0;当n>1时,f(n,m)=[f(n-1,m)+m]%n;有了这个公式,问题就变得多了。
约瑟夫环

实验1 约瑟夫环问题背景约瑟夫问题(Josephus Problem)据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
原题:用户输入M,N值,N个人围成一个环,从0号人开始数,数到M,那个人就退出游戏游戏,直到最后一个人求最后一个剩下的人是几号?问题描述:设编号为1-n的n(n>0)个人按顺时针方向围成一圈.首先第1个人从开始顺时针报数.报m的人(m为正整数).令其出列。
然后再从他的下一人开始,重新从1顺时针报数,报m的人,再令其出列。
如此下去,直到圈中所有人出列为止。
求出列编号序列。
基本要求:需要基于线性表的基本操作来实现约瑟夫问题需要利用数组来实现线性表测试数据:输入:10,3输出:3 6 9 2 7 1 8 5 10 4选做内容:(1)使用单链表来实现之(2)使用循环链表来实现之实验中使用了数组以及链表的操作,来实现对约瑟夫环的解答。
一、先来讲一讲对数组的实现的思路:数组的实现是一种很常规的方法。
这里必须要设置一个临时变量t,在第一轮的循环中,t=0而且在这一轮中要出列的数字是(t+m-1)%i,举例来说:当n=10,m=3时,t=2,4,6,1,3,0,1,1,0,那么就可以知道最后剩下的是4了。
二、再来讲一讲链表的实现方式:在链表的改写中使用到了这几个函数:append(),next(),remove()和prve();这里实现的思路还是比较简单的。
当输入了n个数据后,使用append()函数连接起来,然后用一number来记录这个节点的代表次数。
实验一约瑟夫环问题

实验四约瑟夫环问题一、问题描述设有编号为1,2,…n的n(n>0)个人围成一个圈.每个人持有个密码m。
从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下个人起重新报数,报到m时停止报数,报m的出圈……如此下去,直到所有人全部出圈为止。
当任意给定n和m后,设计算法求n个人出圈的次序。
二、基本要求(1)建立模型,确定存储结构(2)对任意n个人,密码为m,实现约瑟夫环问题(3)出圈的顺序可以依次输出,也可以用一个数组存储三、实验步骤1.需求分析本演示程序用VC++编写,生成一个循环链表,输入人数输入密码,在执行报数输出操作,输出报数序列;①输入的形式和输入值的范围:输入的总共报数人数以及报数密码,在所有输入中,输入数据都为正整数。
②输出的形式:在输出报数顺序是输出报数顺序序号对应报数本身编号。
输出完成后输出是否重新进行提示信息。
③程序所能达到的功能:任意输入的报数人数people,及出列密码num输出报数出列顺序编号。
④测试数据:A.输入报数人数:50,初始化循环链表;B.输入报数密码:3,输出报数出列序列2.概要设计1)为了实现上述程序功能,需要定义循环链表的抽象数据类型:ADT LinkList {数据对象:D={ai|ai∈IntegerSet,i=0,1,2,…,n,n≥0}数据关系:R={<ai,ai+1>|ai,ai+1 ∈D}基本操作:creatcirlink(int n)操作结果:建立循环链表并进行初始化report_num(cirlink &hand,int m,int max)初始条件:循环链表hand已建立;操作结果:报数输出相应的元素data;Game()初始条件:循环链表hand已建立;操作结果:输入报数人people数及密码numMenu()操作结果:在屏幕上显示操作菜单}2)本程序包含4个函数:①主函数main()②显示操作菜单函数menu()③报数出列函数report_num ()④输入人数和密码函数Game()3.详细设计设计实现约瑟夫环问题的存储结构。
约瑟夫环问题小结

约瑟夫环问题⼩结⼀问题描述约瑟夫环问题的基本描述如下:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。
从编号为1的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,要求找到最后⼀个出列的⼈或者模拟这个过程。
⼆问题解法在解决这个问题之前,⾸先我们对⼈物进⾏虚拟编号,即相当于从0开始把⼈物重新进⾏编号,即⽤0,1,2,3,...n-1来表⽰⼈物的编号,最后返回的编号结果加上1,就是原问题的解(为什么这么做呢,下⽂有解释)。
⽽关于该问题的解通常有两种⽅法:1.利⽤循环链表或者数组来模拟整个过程。
具体来讲,整个过程很明显就可以看成是⼀个循环链表删除节点的问题。
当然,我们也可以⽤数组来代替循环链表来模拟整个计数以及出列的过程。
此处只给出利⽤数组来模拟这个过程的解法,最终结果为最后⼀个出列的⼈的编号:#include<iostream>#include<unordered_map>#include<queue>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<sstream>#include<set>#include<map>using namespace std;int main(){int n,m;cin>>n>>m;vector<int>rs(n);for(int i = 0 ; i < n; i++)rs[i] = i + 1;//对⼈物重新进⾏编号,从0开始int cur_index = 0;//当前圆桌状态下的出列⼈的编号int out_cnt = 0;//⽤以表⽰出列的⼈数int cnt = n;//表⽰当前圆桌的总⼈数while(out_cnt < n - 1)//当out_cnt等于n-1时,循环结束,此时圆桌师⽣最后⼀个⼈,即我们要的结果{if(cur_index + m > cnt){if((cur_index + m) % cnt == 0)//这种情况需要单独考虑,否则cur_index就变成负值了cur_index = cnt - 1;elsecur_index = (cur_index + m) % cnt - 1;}elsecur_index = cur_index + m - 1;cnt--;out_cnt++;cout<<"当前出列的为:"<<*(rs.begin() + cur_index)<<endl;rs.erase(rs.begin() + cur_index);//从数组中删去需要出队的⼈员}cout<<"最后⼀个出列的⼈物为:"<<rs[0]<<endl;}该⽅法的时间复杂度为O(nm),空间复杂度为O(n),整个算法的基本流程还是⽐较清晰的,相当于每次循环更新cur_cnt、cnt和out_cnt这三个变量,当out_cnt == n-1时,此时出队的⼈数⼀共有n-1⼈,圆桌上只剩下⼀个⼈了,停⽌循环。
约 瑟 夫 环 问 题 的 三 种 解 法

约瑟夫环问题的简单解法(数学公式法)关于约瑟夫环问题,无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。
我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。
因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。
求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始): k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。
现在我们把他们的编号做一下转换:k-2 – n-2k-1 – n-1解x’ —- 解为x注意x’就是最终的解变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x’=(x+k)%n如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。
(n-2)个人的解呢?当然是先求(n-3)的情况—- 这显然就是一个倒推问题!下面举例说明:假设现在是6个人(编号从0到5)报数,报到(2-1)的退出,即 m=2。
那么第一次编号为1的人退出圈子,从他之后的人开始算起,序列变为2,3,4,5,0,即问题变成了这5个人报数的问题,将序号做一下转换:现在假设x为0,1,2,3,4的解,x’设为那么原问题的解(这里注意,2,3,4,5,0的解就是0,1,2,3,4,5的解,因为1出去了,结果还是一个),根据观察发现,x与x’关系为x’=(x+m)%n,因此只要求出x,就可以求x’。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2009年02月24日星期二下午 05:03问题描述:约瑟夫环问题;有N个人围成一个环,从第一个人开始报数,报到M 的人退出环,并且由他的M值来代替原有的M值,要求输出离开环的顺序。
#include<iostream>#include<stdlib.h>using namespace std;//结点中数据域的类型定义typedef struct{int number;//标号int chipher;//手中的值}DataType;//带头结点的单循环链表typedef struct node{DataType data;struct node *next;}Scnode;//初始化void MyInit(Scnode **head)//指向指针的指针。
{if((*head=(Scnode *)malloc(sizeof(Scnode)))==NULL) exit(1);//动态分配 (*head)->next=*head;}//插入int MyInsert(Scnode *head,int i,DataType x){Scnode *p,*q;int j;p=head->next;j=1;while(p->next!=head&&j<i-1){p=p->next;j++;}if(j!=i-1&&i!=1){cout<<"erro!!!!!!!!!";return 0;}if((q=(Scnode *)malloc(sizeof(Scnode)))==NULL) exit(1); q->data=x;q->next=p->next;p->next=q;return 1;}//删除int MyDelete(Scnode *head,int i,DataType *x){Scnode *p,*q;int j;p=head;j=1;while(p->next!=head&&j<i-1){p=p->next;j++;}if(j!=i-1){cout<<"erro!!!!!!!!!";return 0;}q=p->next;*x=q->data;p->next=p->next->next;free(q);return 1;}//取数据元素int MyGet(Scnode *head,int i,DataType *x){Scnode *p;int j;p=head;j=0;while(p->next!=head&&j<i){p=p->next;j++;}if(j!=i){cout<<"erro!!!!!!!!!";return 0;}*x=p->data;return 1;}//判断是否为空int MyNotEmpty(Scnode *head){if(head->next==head) return 0;else return 1;}//删除P结点所指结点的下一个结点(也就是下面函数中的pre结点的下一个结点) void MyDelete(Scnode *p){Scnode *q=p->next;p->next=p->next->next;free(q);}//关键的函数void MyRing(Scnode *head,int m){Scnode *pre,*curr;int i;pre=head;curr=head->next;while(MyNotEmpty(head)==1)//这个喜欢是外层的把人循环完{for(int i=1;i<m;i++)//注意此处的循环是把当前m值下的人找出来。
{pre=curr;curr=curr->next;if(curr==head)//防止curr结点指向head,为什么呢,因为curr=curr-next移动过程中是要计数的{pre=curr;curr=curr->next;}}cout<<" "<<curr->data.number;m=curr->data.chipher;//这里重新赋值到新的密码m,注意此处的写法curr->data.chiphercurr=curr->next;//从下一个结点开始计数if(curr==head) curr=curr->next;//问题同上。
MyDelete(pre);//删除被指定到的结点}cout<<endl;}void main(){DataType test[7]={{1,3},{2,1},{3,7},{4,2},{5,4},{6,8},{7,4}};int n=7,m=20,i;Scnode *head;MyInit(&head);for(i=1;i<=n;i++)MyInsert(head,i,test[i-1]);MyRing(head,m);}数据结构:约瑟夫环问题的求解,链表数组,简单高效2008-03-25 14:59约瑟夫问题:12个人排成一圈,从1号报数,凡是数到5的人就走出队列(出局),然后继续报数,求最后一个出局的人。
编号为1,2,......,n的n个人按照顺时针方向围坐一圈。
从第一个人开始顺时针方向自1开始报数,报到m时停止报数。
报m 的人出列,从他在顺时针方向的下一个人开始重新报数,如此下去,直到所有人全部出列为止。
方法1:/*** 名称:** 描述:** Copyright: Copyright 2008* 创建日期 Mar 25, 2008* 作者 zhangtianshun* E-mail zhangts8888@* 版本 1.0*/public class JosephCircle {public JosephCircle() {// TODO Auto-generated constructor stub}public static int josephCircle(int totalNum, int perNum) { int count[] = new int[totalNum];for (int i = 0; i < count.length; i++) {count[i] = i + 1;}int flag = 0;int k = 0, n = 0;while (flag != 11) {for (k = 0; k < count.length; k++) {if (count[k] != 0) {n++;if (n % perNum == 0) {count[k] = 0;flag++;}}}}for (k = 0; k < count.length; k++) {if (count[k] != 0) {n = count[k];break;}}return n;}/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubint total = 12;int per = 5;JosephCircle joseph = new JosephCircle(); int last = -1;last = joseph.josephCircle(total, per);System.out.println("最后出列人的编号是: " + last); }}方法2:/*** 名称:** 描述:** Copyright: Copyright 2008* 创建日期 Mar 25, 2008* 作者 zhangtianshun* MSN zhangts8888@* E-mail zhangts8888@* 版本 1.0*/public class Josephus {/*** 约瑟夫环的求解思路:最简单的方法是用循环链表实现.* 现在用数组实现链表的效果.数组下标+1为数字编号,* 数组的值为下一个数组的地址.这样实现了链表的效果.* 当报数count=step-1时,删除下一个节点,节点值赋为-1. * 以此循环,直到数组元素都值为-1,最后删除的即为结果. */public Josephus() {super();}/*** 约瑟夫问题的求解* @param array 待处理的整形数组* @param size 待处理的数组长度* @param step 步长* @return Int 最后出列人的编号.*/public int joseph(int array[],final int size,final int step) { int flag = -1;//初始化数组链表,数组元素的值为下一个节点下标//即为: 1->2->3......(size-1)->0for(int i=0;i<size-1;i++)array[i] = i+1;array[size-1] = 0;/*** intRemain 当前剩下的有效节点* intDeleted 最好删除的一个节点的下班* intCurrent 当前数组元素的下标值* intCount 计数器*/int intRemain,intDeleted,intCurrent,intCount; intRemain = size;intDeleted = -1;intCurrent = 0;intCount = 0;do{//当前节点有效的标准是:不等于-1(flag)if(array[intCurrent] != flag){intCount++;//删除一个节点if(step - intCount == 1){//删除后一个节点,主要是将当前节点的向量指向下一个节点的下一个节点intDeleted = array[intCurrent];array[intCurrent] = array[intDeleted];array[intDeleted] = -1;intRemain--;intCount = 0;}}//当删除最好一个节点元素后,intCurrent的值变为-1.这之后数组就不能再被访问了. intCurrent = array[intCurrent];}while(intRemain !=0 );return intDeleted +1 ;}/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubchar num = '7';System.out.println((int)num);int array[] = new int[12];//人数int size = 12;//出局的倍数int step = 5;int last = -1;Josephus ysf = new Josephus();last = ysf.joseph(array, size, step);System.out.println("最后出列人的编号是: "+last);单循环链表解决约瑟夫环问题]约瑟夫问题的:编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。