Josephus问题求解:
设有n个人围坐一个圆桌周围,,现从第k人开始报数,数到第m的人出列,
然后从出列的下一个重新开始报数,数列的第m个人又出列……如此重复,直
到所有的人全部出列为止。对任意给定的n、k、m,求按出列次序得到的n个
人员的顺序表。
(这个问题看别人用C以数学算法与递归法写出来,代码不过几行,我这上百行的代码确实有点汗颜)
续:算法优化——在每次数到m-1下时,保存当时那个对象的.nextPeron,就不用再重新去找被删除对象的前一个对象了,这里不再修改了。
import java.util.Scanner;
class Person{
int no;
Person nextPerson = null;
public Person(int no){
this.no = no;
}
}
class CycleLink{
Person firstPerson = null; //指向链表第一个人的引用
int len; //定义链表长度
Person temp = null;
int k = 0;
int m = 0;
//设定链表长度
public void setLen(int len){
this.len = len;
}
//从第几个人开始数
public void setK(int k){
this.k = k;
}
//每次数几下
public void setM(int m){
this.m = m;
}
//创建链表
public void createLink(){
for(int i=1; i<=len; i++){
Person p = new Person(i);
//环链的第一个对象
if(i==1){
this.firstPerson = p; //将第一个对象的引用存放在firstPerson中
this.temp = p; //将第一个对象的引用暂时赋于temp,用于接收下一个对象的引用
}
//环链的最后一个对象
else if(i==len){
this.temp.nextPerson = p; //将最后一个对象的引用赋给倒数第二个对象的nextPerson
temp = p; //将当前对象(也就是最后一个对象)的引用暂赋给temp
temp.nextPerson = this.firstPerson; //将第一个对象的引用赋给最后一个对象的nextPerson
}else{
this.temp.nextPerson = p;//将当前对象的引用赋给上一个对象的引用变量nextPerson中
this.temp = p; //将当前对象的引用暂时赋于temp,用于接收下一个对象的引用
}
}
}
//打印环形链表
public void showLink(){
Person t = firstPerson;
do{
System.out.println(t.no);
t = t.nextPerson; /*前一个对象的nextPerson存放的下一个对象的引用
(因为对象也是引用类型,相当于是引用的引用)*/
}while(t!=firstPerson);
}
public void play(){
Person temp = this.firstPerson; //将第一个人这个对象的引用交给temp临时变量
//找到开始数数的人
for(int i=1; i<k; i++){ // i<k是为第k个人这个对象的引用保存在前k前一个人这个对象.nextPerson中
temp = temp.nextPerson; //假设k=2时,循环只执行一次,是将第二个人这个对象的引用交给temp
}
//数m下,找到出列的人 以下注释只符合上面k=2的情况
while(this.len!=1){
for(int i=1; i<m; i++){
//找到出列的对象
temp = temp.nextPerson; /* 这里假设m=3,第一次循temp = 第二个对象的.nextPerson(也就是第三个对象的引用)
第二次循环时temp = 第三个对象的.nextPerson(也就是第四个对象的引用)
从k=2人个开始数,数m=3下,第四个人就是出列的对象,逻辑结论正确!*/
}
System.out.println("第"+temp.no+"个人出列了!");
//找到要出列前一个人(对象) 续:可以在数到m-1时那个对象标记一下,可以不
Person temp2 = temp;
while(temp2.nextPerson!=temp){
temp2 = temp2.nextPerson;
}
//将数到m的人退出圈,即退出环链
temp2.nextPerson = temp.nextPerson; //将出列前一个对象的nextPerson交给出列对象的下一个对象
//让temp指向下一个数数的人
temp = temp.nextPerson;
this.len--;
}
System.out.println("最后留下的人是:"+temp.no);
}
}
public class CycleLinkTest{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.print("请输入圆桌数数游戏的总人数:");
CycleLink t = new CycleLink();
t.setLen(input.nextInt()); //给定环形链表的长度(等同游戏人数)
t.createLink(); //创建环链
// t.showLink(); //测试环链是否创建成功
System.out.print("从第几个人开始数:");
t.setK(input.nextInt());
System.out.print("每次数几下:");
t.setM(input.nextInt());
t.play();
}
}
/*********************
请输入圆桌数数游戏的总人数:7
从第几个人开始数:2
每次数几下:3
第4个人出列了!
第7个人出列了!
第3个人出列了!
第1个人出列了!
第6个人出列了!
第2个人出列了!
最后留下的人是:5
*********************/