单向链表 Josephu(约瑟夫,约瑟夫环)问题
问题表述为:设编号为1,2,...,n的n个人围坐一圈,约定编号为K(1<=k<=n)的人开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依此类推,直到所有人出列为止,由此产生一个出队编号的序列



构建环形队列
package jiegou;
//问题表述为:设编号为1,2,...,n的n个人围坐一圈,
// 约定编号为K(1<=k<=n)的人开始报数,数到m的那个人出列,
// 它的下一位又从1开始报数,数到m的那个人又出列,依此类推,
// 直到所有人出列为止,由此产生一个出队编号的序列
public class JosepfuDemo {
    public static void main(String[] args) {
        CircleSingleLinkList circleSingleLinkList = new CircleSingleLinkList();
        circleSingleLinkList.addBoy(25);
        circleSingleLinkList.show();
        System.out.println("出圈开始");
        circleSingleLinkList.countBoy(1,4,5);
    }
}
// 单向环形链表
class CircleSingleLinkList {
    // 创建 first 节点
    private Boy first = new Boy(-1);
    /**
     *
     * @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;
        // helper 指向尾部停止
        while(true){
            if(helper.getNext() == first){
                break;
            }
            helper = helper.getNext();
        }
        //报数前移动到 startNo 位置
        for(int j=0;j<startNo-1;j++){
            first = first.getNext();
            helper = helper.getNext();
        }
        while(true){
            if(helper == first){
                break;// 圈中只有一个
            }
            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());
    }
    public void addBoy(int nums) {
        if (nums <= 0) {
            System.out.println("nums参数错误");
            return;
        }
        Boy curBoy = null;
        // 使用 for 循环 创建环形链表
        for (int i = 1; i <= nums; i++) {
            // 根据编号创建小孩节点
            Boy boy = new Boy(i);
            // 第一个小孩
            if (i == 1) {
                first = boy;
                first.setNext(first);// 构成一个环
                curBoy = first;// 让 curboy 指向第一个 boy first 不能动
            } else {
                curBoy.setNext(boy); //当前小孩链接新的
                boy.setNext(first); // 新的链接到头部
                curBoy = boy; // 当前指针指向当前这个小孩
            }
        }
    }
    public void show() {
        if (this.first.getNext() == null) {
            System.out.println("链表为空");
            return;
        }
        Boy temp = this.first;
        while (true) {
            System.out.printf("小孩的编号%d\n", temp.getNo());
            if (temp.getNext() == first) { // 遍历完毕
                break;
            }
            temp = temp.getNext();
        }
    }
}
// node
class Boy {
    private int no;//编号
    private Boy next;// 下一个节点
    public Boy(int no) {
        this.no = no;
    }
    public int getNo() {
        return no;
    }
    public Boy getNext() {
        return next;
    }
    public void setNext(Boy next) {
        this.next = next;
    }
    @Override
    public String toString() {
        return "Boy{" +
                "no=" + no +
                '}';
    }
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号