单向链表 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 +
                '}';
    }


}


posted @ 2021-08-15 00:01  brady-wang  阅读(122)  评论(0编辑  收藏  举报