java面试题丢手帕问题 代码详解-- 跟着韩老师学JAVA!!!

         1、约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.)

        2、约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

         3、下面通过java代码来实现这个问题。

/*丢手帕问题
 * 作者:zyj0813
 */
package com.demo;
public class Demo1_2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
CycLink cyclink=new CycLink();
cyclink.setlen(5);      //设置链表长度,默认设置5,读者可以自行修改
cyclink.createLink(); //建立环形链表
cyclink.show();          //展示链表
//开始游戏
cyclink.setk(2);         //默认2,可以自行修改
cyclink.setm(2);        // 默认2,可以自行修改
cyclink.play();
}
}
  
//1、创建一个丢手帕类--小孩类
class Child
{
int no;                   //小孩的编号
Child nextChild;    //定义一个引用类型 下一个小孩
        //构造函数
public Child(int no)
{
this.no=no;
}
}
//2、创建一个环形链表类
class CycLink
{
Child firstChild=null;   //定义第一个小孩
int len=0;                    //初始化链表长度
Child temp=null;         //定义一个跑龙套的变量:作用就相当于指针,用来指向链表中的对象
int k=0;                       //从编号为k的小孩开始数数,数数的时候要从这个小孩开始数
int m=0;                      //每次数数的个数为m个

//5、开始游戏
public void play()
{
Child temp=this.firstChild; //初始化temp指向第一个小孩

 //找到开始游戏的小孩,这里还要遍历,遍历完后temp就是指向开始游戏的小孩
for(int i=1;i<k;i++)
{
temp=temp.nextChild;
}
                 
//下面为在while循环中一次次的排除要出圈的小孩
while(this.len!=1)
{

for(int j=1;j<m;j++)                    //数m下,找到要出圈的小孩,此时temp指向要出圈的小孩
{
temp=temp.nextChild;
}
//找到要出圈的前一个小孩,让这个小孩的的指针直接指向出圈小孩的下一个小孩,实现移除出圈小孩的功能
Child temp2=temp;                   //引用第二个跑龙套为了指向出圈小孩的上一个小孩
while(temp2.nextChild!=temp)  //这里使用了遍历所有链表一次的方法来找到上一个小孩,此方法存在效率低下的缺陷,读者可以自行优化
{
temp2=temp2.nextChild;
}
                                                //将temp2直接指向出圈小孩的下个小孩
temp2.nextChild=temp.nextChild;

temp=temp.nextChild;             //指向下一轮  开始数数的小孩
len--;
}
//打印出最后留下的小孩
System.out.println(temp.no);
}

//设置从编号为k的小孩开始数数
public void setk(int k)
{
this.k=k;
}
//设置数数的个数m
public void setm(int m)
{
this.m=m;
}

//设置链表长度
public void setlen(int len)
{
this.len=len;
}
// 3、初始化环形链表
public void createLink()
{
for(int i=1;i<=len;i++)   //遍历链表中的所有对象
{
if(i==1)                        //初始化第一个对象
{
Child ch=new Child(i);
this.firstChild=ch;
this.temp=ch;      //可以看做(指针)引用temp指向第一个对象
}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;
}
}
 }
}
//4、打印环形链表
public void show()
{
//打印环形链表的时候也要遍历链表,所以也要定义一个跑龙套的引用(指针)temp
Child temp=this.firstChild;
do{
System.out.print(temp.no+" ");
temp=temp.nextChild;
}while(temp!=this.firstChild);  // 这里要使用do while语句,因为while里的条件和初始化定义的temp条件相反,
                                                      //所以要先执行do里的内容让temp向后移动才能让条件不冲突
}
}


猜你喜欢

转载自blog.csdn.net/zyj0813/article/details/78293389