码迷,mamicode.com
首页 > 编程语言 > 详细

约瑟夫环问题 java代码实现(高效率)

时间:2015-06-14 09:36:42      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:约瑟夫问题   java代码   

问题来历编辑

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。[1] 
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
*问题分析与算法设计
约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。这里给出一种实现方法。
这里我使用java数据结构中的双向循环链表
完整代码如下:
<pre name="code" class="java">//约瑟夫问题
package com.test;
public class test {
public static void main(String[] args)  {
            CycLink cycLink= new CycLink(5,2,3);
            
    }
}
class ChildNode{
     int Num;//编号
     ChildNode nextChildNode=null;//指向下一个结点
     ChildNode preChildNode=null;
     public ChildNode(int num){
         this.Num=num;
     }
}
class CycLink{//环形链表
    //先定义一个指向链表第一个结点的引用,指向第一个结点的引用,不能动
    ChildNode TofirstChildNode=null;
    ChildNode temp=null;
    int len=0;//共有多少个结点
    int k=0;//从第几个人开始数数
    int m=0;//数m下
    int n=1;//第n个人出局
    //设置链表大小
    public CycLink(int len,int k,int m){
         this.len=len;//设置环形链表大小
         this.k=k;//设置从第几个人开始数数
         this.m=m;//设置数m下
         creatLink();
         showLink();
         play();
    }
    //开始约瑟夫规则游戏
    private void play(){
        ChildNode cursor=this.TofirstChildNode;
        //1.先开始找到开始数数的人
        for(int i=1;i<k;i++){
            cursor=cursor.nextChildNode;
        }
        while(this.len!=1){
        //2.数m下,找到了要删除的结点
        for(int j=1;j<m;j++){
            cursor=cursor.nextChildNode;
            //其实没人引用了,那么过会儿就会被GC回收
        }
        //3.将数到m的结点,退出圈
         System.out.println("第"+this.n+"次出局的人编号是:"+cursor.Num);
         cursor.preChildNode.nextChildNode=cursor.nextChildNode;//删除操作
         cursor.nextChildNode.preChildNode=cursor.preChildNode;//删除操作
         //让cursor指向下一个开始数数的人,这个动作很重要,不然游标就不动了
         cursor=cursor.nextChildNode;
         this.len--;//出圈一个人,
         this.n++;
        }
        //最后一个剩下的结点
        System.out.println("最后还在桌子上坐着的人编号:"+cursor.Num);
    }
    //初始化环形链表
    private void creatLink(){
        for(int i=1;i<=len;i++){
            if(i==1){
            //创建第一个结点
            ChildNode ch=new ChildNode(i);
            this.TofirstChildNode=ch;
            temp=ch;
           }
            else{
                //创建最后一个结点
                if(i==len){
                    ChildNode ch=new  ChildNode(i);
                    temp.nextChildNode=ch;
                    ch.preChildNode=temp;
                    temp=ch;
                    temp.nextChildNode=this.TofirstChildNode;
                    this.TofirstChildNode.preChildNode=ch;
                }
                else{
                //继续创建结点
                 ChildNode ch=new  ChildNode(i);
                 temp.nextChildNode=ch;
                 ch.preChildNode=temp;
                 temp=ch;
               }
            }
        }
    }
    //打印环形链表
    private void showLink(){
        //定义一个游标
       ChildNode cursor=this.TofirstChildNode;
       do{
           System.out.println("参员编号为:"+cursor.Num);
           cursor=cursor.preChildNode; 
       }
       while(cursor!=this.TofirstChildNode);
    }
}


运行结果:
参员编号为:1
参员编号为:5
参员编号为:4
参员编号为:3
参员编号为:2
第1次出局的人编号是:4
第2次出局的人编号是:2
第3次出局的人编号是:1
第4次出局的人编号是:3
最后还在桌子上坐着的人编号:5

约瑟夫环问题 java代码实现(高效率)

标签:约瑟夫问题   java代码   

原文地址:http://blog.csdn.net/uniquewonderq/article/details/46484335

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!