约瑟夫环(丢手帕游戏)Java 链表实现
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
例如:n = 9, k = 1, m = 5
【解答】
出局人的顺序为5, 1, 7, 4, 3, 6, 9, 2, 8。
Tip:以下为单链表实现,处理出局结点时效率不高,可以考虑用循环链表实现,大家有兴趣自己尝试一下。
/*
* 作者:winHan
* 日期:2011.4.5
* 功能:(丢手帕问题)Joseph环问题(链表实现)
*/
package com.lin;
public class Joseph
{
public static void main(String[] args)
{
System.out.println("【约瑟夫环数数问题(丢手帕问题)】");
CycLink cyclink=new CycLink();
cyclink.setLen(5); //玩游戏的人数
cyclink.createLink();//创建链表
cyclink.setK(2); //2号开始
cyclink.setM(2); //数两下 ,数到2的退出圈
cyclink.show();
cyclink.play();
}
}
//*******************************************************一
class Child //节点类
{
int no;//编号
Child nextChild=null;//不指向任何结点
public Child(int no)//构造函数,目的:给一个编号
{
this.no=no;
}
}
//*******************************************************二
class CycLink//链表类
{
//先定义一个指向首节点引用
Child firstChild =null;//将其固定不动
Child temp=null;//temp作浮标
int len=0;//共有几个人
int k=0;//数数开始的编号
int m=0;//数m下
1
public void setLen(int len)//设置链表大小
{
this.len=len;//共有几个人玩游戏
System.out.println("参加人数:"+this.len+"人");
}
2
public void setK(int k)//设置开始从第几个人数数
{
this.k=k;
System.out.println("开始数数的人的编号:"+this.k+"号");
}
3
public void setM(int m)//设置数到几才退出
{
this.m=m;
System.out.println("规则:数到"+this.m+"退出");
}
4
public void play()//开始玩游戏
{
Child temp=this.firstChild;
//1.找到开始数数的人编号k
for(int i=1;i<k;i++)//注意他自己也数了一次
{
temp=temp.nextChild;
}
while(this.len!=1)
{
//2.从游戏开始那个人起,数m下
for(int j=1;j<m;j++)//包括自己数的一次
{
temp=temp.nextChild;
}
//找到本次要出圈结点的前一个结点
Child pre_Temp=temp;//创建一个临时浮标
while(pre_Temp.nextChild!=temp)
{
pre_Temp=pre_Temp.nextChild;
}
//3.数到m的退出圈
pre_Temp.nextChild=temp.nextChild;
//继续遍历
temp=temp.nextChild;
this.len--;//出去一个,环形链表长度减一
}
//输出最后一个结点
System.out.println("/n游戏最后出圈小孩的编号为:"+temp.no+"号");
}
//*******************************************************三
//建立环形链表(单链)
public void createLink()
{
for(int i=1;i<=len;i++)
{
if(i==1)
{
//创建第一个结点
Child ch=new Child(i);
this.firstChild=ch;
this.temp=ch;
}
else
{
if(i==len) //对于最后一个结点
{
//创建最后一个结点
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
temp.nextChild=this.firstChild;
}
else
{
//继续创建结点
Child ch=new Child(i);
temp.nextChild=ch;//指向新创建的结点
temp=ch; //temp游标向前走一步
}
}
}
}
//*******************************************************四
//打印该环形链表
public void show()
{
//使用一个浮标遍历
Child temp=this.firstChild;
System.out.print("编号并输出单环形链表-->");
do{
System.out.print("编号"+temp.no+" ");
temp=temp.nextChild;//浮标后移
}while(temp!=this.firstChild);
}
}