丢手帕问题 (约瑟夫问题)Java实现

问题:

丢手帕游戏是约瑟夫问题的一个变种,游戏很简单,N个小孩围成一个圈,标号为1到N,从编号为m的小孩开始报数,报到第L个小孩退出游戏,然后下一个小孩继续从1开始报数,数到第L个小孩退出游戏,如此循环,直到剩下最后一个小孩是胜利者.

 

使用环形链表方式解决问题:

代码如下:

/**
 * 描述:
 * @作者:niexiaohui
 * @创建时间:2016年12月27日
 * @修改记录:
 */
public class Test {
    public static void main(String[] args) {
        long starttime=System.currentTimeMillis();
        CircleLinkList game=new CircleLinkList(10000, 99, 533);
        long endtime=System.currentTimeMillis();
        game.play();
        long time2=System.currentTimeMillis();
        System.out.println("创建链表用了"+(endtime-starttime)/1000.0+"秒");
        System.out.println("玩游戏共用了"+(time2-starttime)/1000.0+"秒");
    }
}

class Child{
    protected int no;
    protected Child nextChild;
    public Child(int no){
        this.no=no;
    }
}

class CircleLinkList{
    /**
     * 参与游戏人数
     */
    private int playBoys;
    /**
     * 从第几个开始数
     */
    private int startIndex;
    /**
     * 数几个小孩退出
     */
    private int countNum;
    //首个小孩
    private Child firstChild;
    //标识当前小孩
    private Child temp;
    /**
     * 
     * @param playBoys 参与游戏人数
     * @param startIndex 从第几个开始数
     * @param countNum 数几个小孩退出
     */
    public CircleLinkList(int playBoys, int startIndex, int countNum) {
        super();
        this.playBoys = playBoys;
        this.startIndex = startIndex;
        this.countNum = countNum;
        createList();
    }
    /**
     * 创建循环链表
     */
    private void createList() {
        for (int i = 1; i <=playBoys; i++) {
            if (i==1) {//第一个小孩
                Child child=new Child(i);
                this.firstChild=child;
                this.temp=child;
            }else if (i==playBoys) {//最后一个小孩
                Child child=new Child(i);
                this.temp.nextChild=child;
                this.temp=child;
                this.temp.nextChild=this.firstChild;//最后一个小孩的下一个小孩指向第一个小孩
            }else {
                Child child=new Child(i);
                this.temp.nextChild=child;
                this.temp=child;
            }
        }
    }
    
    /**
     * 玩游戏
     */
    public void play(){
        temp=firstChild;
        //先找到从第几个小孩开始数
        for (int i = 1; i < startIndex; i++) {
            temp=temp.nextChild;
        }
        System.out.println("游戏开始,从第"+temp.no+"个小孩开始数,数到第"+this.countNum+"个小孩退出游戏");
        while (this.playBoys>1) {
            //找到要退出游戏的前一个小孩
            for (int i = 1; i < countNum-1; i++) {
                temp=temp.nextChild;
            }
            //当前temp是要退出的前一个小孩
            Child leaveChild=temp.nextChild;//要退出的小孩
            System.out.println("当前退出的小孩编号为:" +leaveChild.no);
            temp.nextChild=leaveChild.nextChild;
            if (leaveChild.no==firstChild.no) {//如果要退出的小孩是第一个小孩,则将第一个小孩重置为退出小孩的下一个小孩
                this.firstChild=leaveChild.nextChild;
            }
            temp=temp.nextChild;
            this.playBoys--;//玩游戏人数少一个
        }
        System.out.println("最后剩下的小孩是:"+ temp.no);
    }
}

代码虽然不少,但是并不难懂,有过一点数据结构基础的还是很容易理解的.

 

使用数组方式解决问题:

 

代码如下:

 

/**
 * 描述:
 * 
 * @作者:niexiaohui
 * @创建时间:2017年1月11日
 * @修改记录:
 */
public class Test4 {

    public static void main(String[] args) throws InterruptedException {
        long starttime = System.currentTimeMillis();
        int childrens=10000;//玩游戏的小孩总数
        int countNum=533;//数第几个小孩退出游戏
        int startNum=99;//开始从第几个人开始数
        int count=1;//计数器
        int [] arrays=new int[childrens];
        for (int i = 0; i < arrays.length; i++) {//为数组初始化值
            arrays[i]=1;
        }
        loop:while(true){
            for (int i = 0; i < arrays.length; i++) {
                if (i<startNum-1) {//第一次循环找到从第几个小孩开始数数
                    continue;
                }
                startNum=0;//开始后将startNum清零
                if (arrays[i]!=0) {//值为0的表示已经退出游戏
                    if (count%countNum==0) {//数到的小孩退出游戏
                        if (childrens==1) {
                            System.out.println("游戏胜利的小孩编号为:"+(i+1));
                            break loop;
                        }
                        arrays[i]=0;//退出游戏的小孩值设为0
                        count=0;//计数器清零,重新计数
                        childrens--;//玩游戏的人数减一
                        System.out.println("编号为"+(i+1)+"的小孩退出游戏");
                    }
                    count++;
                }
            }
        }
        long time2 = System.currentTimeMillis();
        System.out.println("玩游戏共用了" + (time2 - starttime)/1000.0 + "秒");
    }

    

}

 

 

用数组方式解决问题代码少了很多,效率上,我大致比较了下,随着数到第L个小孩退出游戏,即L的增大,链表的速度会提升,相反数组会下降,如果L值很小的话,数组的效率是高于链表的效率的.

 

posted @ 2017-01-13 14:58  万界漂泊者  阅读(2634)  评论(0编辑  收藏  举报