约瑟夫环(JosePhu)

  1. 实现图解
  2. 代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
出圈的实现思路:
在这里插入图片描述
代码实现:

package com.demo;

public class JosePhu {
    
    
    public static void main(String[] args) {
    
    
        //测试看看创建和遍历环形链表是否正确
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy( 5 );//加入5个小孩
        circleSingleLinkedList.showBoy();

        //出圈顺序
        circleSingleLinkedList.countBoy( 1, 2, 5 );

    }

}


//创建一个Boy类 表示一个节点
class Boy {
    
    
    private int no;//编号
    private Boy next;//指向下一个节点,默认null

    public Boy(int no) {
    
    
        this.no = no;
    }

    public void setNo(int no) {
    
    
        this.no = no;
    }

    public void setNext(Boy next) {
    
    
        this.next = next;
    }

    public int getNo() {
    
    
        return no;
    }

    public Boy getNext() {
    
    
        return next;
    }
}

//创建一个环形的单向链表
class CircleSingleLinkedList {
    
    
    //创建一个first节点,当前没有编号
    private Boy first = null;

    //添加小孩节点,构建一个环形的链表
    public void addBoy(int nums) {
    
    
        if (nums < 1) {
    
    

            System.out.println( "nums的值不正确" );
            return;//结束
        }

        Boy curBoy = null;  //辅助指针,first不能动需要一个辅助指针
        //使用for循环,创建环形链表
        for (int i = 1; i <= nums; i++) {
    
    
            //根据编号,创建小孩节点
            Boy boy = new Boy( i );
            if (i == 1) {
    
    
                first = boy;
                first.setNext( first );//创建了环形链表
                curBoy = first;//指向第一个小孩
            } else {
    
    
                curBoy.setNext( boy );//使循环的那条线指向下一个节点
                boy.setNext( first );//构建了循环线
                curBoy = boy;//curBoy总是指向最后一个节点


            }

        }


    }

    //    写下一个方法遍历当前的环形链表
    public void showBoy() {
    
    

        //判断链表是否为空
        if (first == null) {
    
    

            System.out.println( "没有孩子节点,链表为空" );
            return;//终止
        }
        //因为first不能动,所以需要辅助指针
        Boy curBoy = first;
        while (true) {
    
    
            System.out.printf( "小孩的编号%d\n", curBoy.getNo() );
            if (curBoy.getNext() == first) {
    
    //说明遍历完毕
                break;//退出
            }
            curBoy = curBoy.getNext();//继续下一个

        }


    }


    //根据用户的输入,计算出小孩出圈的方法
    /*
     * @param startNo 表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @param nums 表示总共多少个小孩
     * */

    public void countBoy(int startNo, int countNum, int nums) {
    
    
        //对输入的数据进行校验
        if (first == null || startNo < 1 || startNo > nums) {
    
    
            System.out.println( "输入的数据有误,please input again" );
            return;//终止

        }
        //创建辅助指针完成小孩出圈,而且辅助指针指向最后一个节点
        Boy helper = first;
        while (true) {
    
    
            if (helper.getNext() == first) {
    
    //说明helper指向最后的小孩节点
                break;


            }
            helper = helper.getNext();

        }


//        小孩报数前先让frist和helper移动k-1次(k代表小孩报数的位置)
        for (int i = 0; i < startNo - 1; i++) {
    
    
            first = first.getNext();
            helper = helper.getNext();


        }

        //当小孩报数时first和helper先移动m-1次,然后出圈
        //这是一个循环的操作,直到圈中只有一个节点
        while (true) {
    
    
            if (helper == first) {
    
    //只有一个节点
                break;
            }
//first和helper先移动m-1次,然后出圈
            for (int i = 0; i < countNum - 1; i++) {
    
    
                first = first.getNext();
                helper = helper.getNext();

            }
            //这时first指向的就是要出圈的小孩节点
            System.out.printf( "出圈小孩节点%d\n", first.getNo() );
            //让小孩节点出圈操作
            first = first.getNext();
            helper.setNext( first );//这两步使出圈的节点消失
        }
        System.out.printf( "最后圈中的节点%d\n", first.getNo() );


    }
}

成功后:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/houzhicongone/article/details/113858664