Java | Josephu(约瑟夫)问题

Josephu问题

/*
 * Josephu问题:
 *  设编号为1,2,...,n的n个人围坐一圈,约定编号为k(1 <= k <= n)的人从1开始报数,数到m的那个人出列,它的下一位
 *  又从1开始报数,数到m的那个人又出列,依此类推,直到所有人出列为止,由此产生一个出队编号的序列。
 *
 * 用一个不带头结点的循环链表来处理Josephu问题:
 *  构建一个单项的环形链表思路:
 *      1. 先创建第一个节点,让first指向该节点,并形成环形
 *      2. 后面当我们每创建一个新的节点,就把该节点加入到已有的环形链表中即可
 *  遍历环形链表
 *      1. 先让一个辅助指针(变量)curBoy,指向first节点
 *      2. 然后通过一个while循环遍历该环形链表即可
 * 举例:
 *  n = 5,即有5个人
 *  k = 1,从第一个人开始报数
 *  m = 2,数2下
 *  出圈的顺序:2 -> 4 -> 1 -> 5 -> 3
 */

Boy类

class Boy{
    private int id;
    private Boy next;

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

    public Boy(Boy boy) {
        this.id = boy.id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Boy getNext() {
        return next;
    }

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

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

CircleSingleLinkedList类

class CircleSingleLinkedList{
    private Boy first = null;
    // 添加小孩节点,构建成一个环形链表
    public void addBoys(int nums){
        if (nums < 1)
            throw new RuntimeException("小孩数量有误!");
        Boy boy = null;
        Boy curBoy = null;
        for (int i = 1; i <= nums; i++) {
            boy = new Boy(i);
            if (first == null){
                first = new Boy(boy);
                first.setNext(first);
                continue;
            }
            curBoy = first;
            while (curBoy.getNext().getId() != first.getId()){
                curBoy = curBoy.getNext();
            }
            curBoy.setNext(boy);
            boy.setNext(first);
        }
    }
    // 遍历当前的环形链表
    public void showBoy(){
        Boy curBoy = first;
        System.out.println(first);
        while (curBoy.getNext() != null){
            curBoy = curBoy.getNext();
            if (curBoy.getId() == first.getId())
                return;
            System.out.println(curBoy);
        }
    }
    // 根据用户的输入,计算出小孩出圈的顺序
    public void countBoy(int startId,int countNum,int nums){
        addBoys(nums);
//        showBoy();
        Boy curBoy = first;
        int count = 1;  // flag = 0时用于记录是否开始游戏,flag = 1时用于记录是否到达countNum
        boolean startGame = false;   // 判断是否开始游戏,即第一次循环到编号startId的小孩
        while (curBoy.getNext() != null){
            curBoy = curBoy.getNext();
            if (curBoy.getNext().getId() == first.getId())
                break;
        }
        while (curBoy.getNext() != curBoy){
            if (!startGame && count == startId){
                count = 1;
                startGame = true;
            }
            if (startGame && count == countNum){
                System.out.println(curBoy.getNext() + "出圈");
                curBoy.setNext(curBoy.getNext().getNext());
                count = 1;
            }
            curBoy = curBoy.getNext();
            count ++;
        }
        System.out.println(curBoy + "出圈");
    }
}

代码测试

@Test
public void test(){
    CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
    circleSingleLinkedList.countBoy(1,2,5);
}

结果输出

Boy{id=2}出圈
Boy{id=4}出圈
Boy{id=1}出圈
Boy{id=5}出圈
Boy{id=3}出圈
发布了36 篇原创文章 · 获赞 3 · 访问量 6211

猜你喜欢

转载自blog.csdn.net/Oh_MyBug/article/details/104909415
今日推荐