Java Joseph 问题

Java Joseph 问题: 

Joseph 问题为:设编号为1,2,3......n 的 n 个人围坐一起,约定编号为 k  (1<=k<=n) 的人从1开始报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,以此类推,知道所有的人出列为止,由此产生一个出队编号的序列。

提示:

用一个不带头结点的循环链表来处理 Joseph 问题:先构成一个有 n 个结点的单循环链表,然后由k结点从1开始计数,计数到m,对应的结点从链表中删除,然后再从被删除结点的下一个结点由从1开始计数,知道最后一个结点从链表中删除,算法结束。

解题思路:

整体代码:

/*
 *    项目名称:ANA
 *    文件名称:CircleSingleLickedListDemo.java
 *    Date:2023/9/25 上午11:00
 *    Author:yan_Bingo
 */

package Learning;

/**
 * @author Yan_Bingo
 * @version 1.0
 * Create by 2023/9/25 11:00
 */

public class CircleSingleLickedListDemo {
    public static void main(String[] args) {
        CircleSingleLickedList circleSingleLickedList = new CircleSingleLickedList();
        circleSingleLickedList.addBoy(5);

        System.out.println("输出循环链表的情况");
        circleSingleLickedList.showCircleList();

        System.out.println();
        circleSingleLickedList.countBoy(1, 2, 5);
    }
}

class CircleSingleLickedList{
    private Boy first = null;
    // 指定添加 nums 个小孩
    public void addBoy(int nums){
        // 如果输入要添加的数量小于1,直接返回
        if(nums < 1){
            System.out.println("输入的数量小于1");
            return;
        }
        Boy curBoy = null; // 设置一个中间中间变量记录当前循环链表的最后一个
        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;
            }

        }
    }

    // 输出链表的情况
    public void showCircleList(){
        if(first == null){
            System.out.println("当前的链表为空,无法查询~~~");
        }
        Boy curBoy = first;
        while (true){

            System.out.println(curBoy);
            if(curBoy.getNext() == first){
                break;
            }
            curBoy = curBoy.getNext();
        }
    }

    /**
     *
     * @param startNo 表示从第几个小孩开始
     * @param k 表示小孩数几下出圈
     * @param nums 表示一共有多少个小孩
     */
    // 输入小孩出圈的顺序
    public void countBoy(int startNo, int k, int nums){
        if(startNo < 1 || k < 1 || nums < 1 || first == null || startNo > nums){
            System.out.println("输入的参数有误,请重新输入");
            return;
        }
        Boy helper = first;
        while (true){
            if(helper.getNext() == first){
            //    说明这时 helper 的下一位就是first 即 最后一个小孩的位置
                break;
            }
            helper = helper.getNext();
        }
        // 将 first 和 helper 移动到 第 startNo 个和第 startNo-1 的位置
        for (int i = 0; i < startNo-1 ; i++) {
            first = first.getNext();
            helper = helper.getNext();
        }

        for (int i = 1; i < nums ; i++) {
            if(helper == first){
                break;
            }
            for (int j = 1; j < k; j++) {
                first = first.getNext();
                helper = helper.getNext();
            }
            System.out.printf("编号为%d的小孩出圈了\n", first.val);

            first = first.getNext();
            helper.setNext(first);

        }
        // 输入最后一个小孩出圈
        System.out.printf("编号为%d的小孩出圈了", first.val);
    }

}

class Boy{
    public int val;
    public Boy next;

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

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }

    public Boy getNext() {
        return next;
    }

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

    @Override
    public String toString() {
        return "Boy{" +
                "val=" + val +
                '}';
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值