数据结构 - 链表(单向环形链表)(约瑟夫问题)

问题如下(与分析)

在这里插入图片描述在这里插入图片描述

构建思路

在这里插入图片描述

输入一个数,数到这个数的小孩出圈,出圈顺序的思路

在这里插入图片描述

代码实现

根据图解,来一步一步实现
  //根据用户输入,计算小孩出圈顺序

    /**
     *
     * @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("输入有误,重新输入");
            return;
        }
        //创建辅助指针,帮助出圈
        Boy helper = first;

        while (true){
            if (helper.getNext() == first){ //说明helper指向最后小孩节点
                break;
            }
            helper = helper.getNext();
        }
        //小孩报数前,先让first 和 helper 移动 k - 1 次
        for (int j = 0; j < startNo -1; j++){
            first = first.getNext();
            helper = helper.getNext();
        }
        //当小孩报数时,让first 和 helper 指针同时 移动 m - 1 次,然后出圈
        //这里是一个循环操作,直到圈中只有一个小孩
        while (true){
            if (helper == first){ //说明只有一个节点
                break;
            }
            //让first 和 helper 同时移动 countNum - 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 = first.getNext();
            helper.setNext(first);
        }
        System.out.println("最后留在圈中的小孩编号:"+first.getNo());
    }
}

测试

CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();

circleSingleLinkedList.addBoy(5); //加入五个小孩节点

//测试小孩出圈
circleSingleLinkedList.countBoy(1,2,5);


结果:
小孩 2 出圈
小孩 4 出圈
小孩 1 出圈
小孩 5 出圈
最后留在圈中的小孩编号:3

完整代码

package DataStructures.LinkedList;

/**
 * 约瑟夫问题
 */
public class Josepfu {
    public static void main(String []args){
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5); //加入五个小孩节点

        //遍历
        //circleSingleLinkedList.showBoy();

        //测试小孩出圈
        circleSingleLinkedList.countBoy(1,2,5);
    }
}
//创建一个环形单向链表
class CircleSingleLinkedList{
    //创建一个first节点,当前没有编号
    private Boy first = null;

    //遍历环形链表
    public void showBoy(){
        //先判断是否为空
        if (first == null){
            System.out.println("链表为空");
            return;
        }
        //因为first不能动,要用辅助指针完成遍历
        Boy cur = first;
        while (true){
            System.out.printf("小孩的编号是:%d \n",cur.getNo());
            if (cur.getNext() == first){ //遍历完
                break;
            }
            cur = cur.getNext(); //后移
        }
    }
    //添加小孩节点,构建环形链表
    public void addBoy(int nums){
        //验证nums
        if (nums<1){
            System.out.println("nums的值不正确");
            return;
        }

        Boy cur = null; //辅助指针帮助构建环形链表

        //使用for来构建环形链表
        for (int i = 1; i <= nums; i++){
            //根据编号创建小孩节点
            Boy boy = new Boy(i);
            //如果是第一个小孩
            if (i == 1){
                first = boy;
                first.setNext(first); //构成一个环
                cur = first; //让cur指向第一个小孩,first不能动
            } else {
                cur.setNext(boy);
                boy.setNext(first);
                cur = boy;
            }

        }
    }

    //根据用户输入,计算小孩出圈顺序

    /**
     *
     * @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("输入有误,重新输入");
            return;
        }
        //创建辅助指针,帮助出圈
        Boy helper = first;

        while (true){
            if (helper.getNext() == first){ //说明helper指向最后小孩节点
                break;
            }
            helper = helper.getNext();
        }
        //小孩报数前,先让first 和 helper 移动 k - 1 次
        for (int j = 0; j < startNo -1; j++){
            first = first.getNext();
            helper = helper.getNext();
        }
        //当小孩报数时,让first 和 helper 指针同时 移动 m - 1 次,然后出圈
        //这里是一个循环操作,直到圈中只有一个小孩
        while (true){
            if (helper == first){ //说明只有一个节点
                break;
            }
            //让first 和 helper 同时移动 countNum - 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 = first.getNext();
            helper.setNext(first);
        }
        System.out.println("最后留在圈中的小孩编号:"+first.getNo());
    }
}
//先创建一个Boy类,表示一个节点
class Boy{
    private int no;
    private Boy next;
    public Boy(int no){
        this.no = no;
    }

    public int getNo() {
        return no;
    }

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

    public Boy getNext() {
        return next;
    }

    public void setNext(Boy next) {
        this.next = next;
    }
}
发布了83 篇原创文章 · 获赞 61 · 访问量 9199

猜你喜欢

转载自blog.csdn.net/weixin_43736084/article/details/101999126