美文网首页数据结构与算法-java实现
java算法实现之约瑟夫问题(Josephu)

java算法实现之约瑟夫问题(Josephu)

作者: 先生zeng | 来源:发表于2019-06-13 21:11 被阅读0次
约瑟夫问题 image.png

首先这个问题我们可以很清楚的看出来,可以使用单向环形队列的数据结构来代入这个问题。
我先来分析一下这道题的思路:
第一步,确定是单向环形链表后,我们需要先构建这样一个数据结构,
由于每个人的最后都出列后,这个队伍中的人数为0,因此我们不需要设置头节点,比较简便。所以我们先构建一个,包含编号、指向下一个节点的类。

class Baby{

    //编号
    private int no;
    //指向下一个节点
    private Baby next;
//get\set....
}

2.队列有了,那么我们第二部,就需要普通的数据结构都需要有的基本方法,遍历,新增,修改,删除。。。根据题意,只需要遍历(用于测试)还有新增,就足够了。所以我们在新建一个内部类,把该单向环形链表作为私有类,写一些常用方法来操作它。

class CircleSingleLinkedList{

    //创建一个fist节点
    private Baby first=new Baby(-1);
    //添加一个小孩,构建一个环形链表
    public void addBaby(int nums){
        //nums 代表要添加几个小孩
        if(nums<1){
            System.out.println("nums值,不正确");
            return ;
        }

        //辅助指针帮助构建环形链表
        Baby curBaby=null;
        //使用一个for循环,来创建我们的环形链表
        for (int i=1;i<=nums;i++){
            //根据编号,创建小孩节点
            Baby baby = new Baby(i);
            if(i==1){
                first=baby;
                first.setNext(first);
                curBaby=first;
            }else{
                curBaby.setNext(baby);
                baby.setNext(first);
                curBaby=baby;
            }
        }
    }

    /**
     * 遍历当前环形链表
     */
    public void list(){
        if(first.getNext()==null){
            System.out.println("该链表为null");
            return ;
        }
        Baby curBaby=first;
        while (true){
            System.out.println("小孩的编号为:"+curBaby.getNo());
            if(curBaby.getNext()==first) {
                break;
            }
            curBaby = curBaby.getNext();
        }
    }
第三步,我们再来考虑,如何出队列的问题。通常遇到这种数据结构的问题,一定要思路清晰。越是复杂的数据处理,最最基本的数据结构越需要先理清楚出来,再来去思考,最复杂的需要怎么实现。下图是实现的思路 image.png

为什么需要一个辅助指针,这个指针,是作为每次报数后,出链表的前一个元素,用来指向后一个元素(也就是删除那个元素的,这个时候,被删除的元素由于没有被引用了,就会被垃圾回收了)

还有一点,两个节点同时移动的次数,其实就是出列后,从下一个节点作为1开始计算的次数。
代码如下:

  /**
     *  根据用户输入,计算小孩出圈的顺序
     * @param startNo  表示从第几个小孩开始数数
     * @param countNum  表示数几下
     * @param nums       表示最初多少个小孩在圈中
     */
    public void countBaby(int startNo,int countNum,int nums){
        if(first == null || startNo<1 || startNo>nums){
            System.out.println("输入参数有误,请重新输入");
            return ;
        }
        //创建要给辅助指针,帮助小孩出圈
        Baby helper=first;
        //需求创建一个辅助指针,helper,事先应该指向环形链表的最后一个节点
        while(true){
            //说明helper指向最后一个小孩节点
            if(helper.getNext()== first){
                break;
            }
            helper=helper.getNext();
        }
        //报数之前,我们还有一个参数是从第几个人之中开始出队列的,于是我们需要把辅助节点还有first节点一起移动到startNo-1的位置
        for (int i=0;i<startNo-1;i++){
                first=first.getNext();
                helper=helper.getNext();
            }

        //小孩报数时,让两个指针同时移动countNum-1次
        while (true){

            if(helper==first){
                break;
            }
            for(int i=0;i<countNum-1;i++){
                first=first.getNext();
                helper=helper.getNext();
            }
            System.out.println("出列的人编号为:"+first.getNo());
            first=first.getNext();
            helper.setNext(first);
        }
        System.out.println("出列的人编号为"+first.getNo());
    }

好了,以上就是约瑟夫问题的java解法实现。

感谢您阅读我的文章,如果满意可以帮我点歌赞,谢谢哈。
如果对文章部分还有什么见解或者疑惑,可以私信评论我,欢迎技术讨论。如果需要获取完整的文件资源,可以加我微信z985085305,获取我整理的全套笔记。
思想的碰撞最能促进技术的进步哦。

相关文章

网友评论

    本文标题:java算法实现之约瑟夫问题(Josephu)

    本文链接:https://www.haomeiwen.com/subject/psrrfctx.html