Josephu问题:
设编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数, 数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
提示:用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点的人从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
1.设计child链表。
包括当前child编号,以及下一个child指向
int num;
Child nextChild;
public Child(int num){
this.num = num; //创建构造器,获取当前child编号
}
2.设计玩法
Child firstChild=null; //指向第一个玩家,不能修改
Child nowChild=null; //当前指针指向的玩家
int length=0; //参与游戏人数
int k=0; //从谁开始
int m=0; //每回合计算数,到m就将玩家踢出局
public void setM(int m){
this.m = m;
}
public void setLength(int length){
this.length=length;
}
public void setK(int k){
this.k=k;
}
public void play(){
//将指针指向指定第一位玩家
Child nowChild = this.firstChild;
//找到开始玩家
for(int i=1;i<k;i++){
nowChild=nowChild.nextChild;
}
//开始计算,每当计算到m时,玩家出局,循环直至最后一人
while(this.length!=1){
for(int j=1;j<m;j++){
nowChild = nowChild.nextChild;
}
//找到当前指针指向的上一个玩家,修改他的下一位玩家,保持链表链接
child preChild=nowChild;
while(preChild.nextChild!=nowChild){
preChild=preChild.nextChild;
}
//将数到m的玩家踢出游戏
preChild.nextChild=nowChild.nextChild;
Syso("出圈的是:"+nowChild.num);
//指针指向下一位玩家
nowChild=nowChild.nextChild;
//由于玩家被踢出,人数-1
this.length--;
}
//最终玩家
Syso("最终出圈的是:"+nowChild.num);
}
//将列表转变成环形链表
public void createLink(){
for(int i=1;i<=length;i++){
//设置第一个玩家并移动指针
if(i==1){
Child child = new Child(i);
this.firstChild=child;
nowChild=child;
}else{
//设置最后一个玩家并移动指针
if(i==length){
Child child = child(i);
nowChild.nextChild=child;
nowChild = child;
nowChild = this.firstChild;
}else{
//循环设置玩家并移动指针
Child child = new Child(i);
nowChild.nextChild=child;
nowChild=child;
}
}
}
}
//遍历玩家列表
public void show(){
Child nowChild = this.firstChild;
do{
Syso(nowChild.num+" ")
}while(nowChild!=this.firstChild);
Syso();
}
3.程序入口
.setLength()
.createLink();
.setK()
.setM()
.show()
.play()