约瑟夫问题(环形链表)

264 阅读2分钟

问题描述

  有n个孩子,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会出列,然后从第m+1个人开始,重复以上过程。在游戏结束后,问n个孩子的出列顺序?

解决方法

  (1)使用环形单链表解决该问题,首先将n个节点连接在一块成为一个环形链表,有第一个节点开始,数到m则删除该节点,然后重新报数,直到链表中只剩下最后一个节点。此时最后一个节点仍然是环形,则仍可报数到m,为最后出列。
  (2)使用数组模拟解决
  (3)使用递归方法解决
  这里采用环形单链表解决。

代码实现(java)

这里创建环形单链表时首先将一个节点加入并构成一个环形,也可以先把所有节点加入,构成一个单链表,再将第一个节点和最后一个节点连接起来。

package com.Josephu;

public class Josephu {
    public static void main(String[] args) {
        JosephuLinkedList jList = new JosephuLinkedList(5);
        jList.josephuList();
        jList.showJosephuList();
        jList.JossephuGame(2);
    }
}

class Children {
    private int no;
    private Children next;

    public Children (int no) {
        this.no = no;
    }

    public int getNo() {
        //获取编号
        return no;
    }

    public Children getNext() {
        //获取下一个Children节点
        return next;
    }

    public void setNext(Children next) {
        //设置下一个Children节点
        this.next = next;
    }
}

class JosephuLinkedList {
    Children first = null;
    //Children总个数
    private int sum;
    public JosephuLinkedList (int sum) {
        this.sum = sum;
    }
    //根据总人数设置环形链表
    public void josephuList () {
        Children currentChild = null;
        for(int i = 1; i <= sum; i++) {
            Children child = new Children(i);
            if (i == 1) {
                first = child;
                first.setNext(first);
                currentChild = first;
            } else {
                child.setNext(first);
                currentChild.setNext(child);
                currentChild = child;
            }

        }
    }

    //遍历环形链表
    public void showJosephuList () {
        Children currentChild = first;
        System.out.println("环形链表中的编号为:");
        while (currentChild.getNext() != first) {

            System.out.println(currentChild.getNo());
            currentChild = currentChild.getNext();
        }
        System.out.println(currentChild.getNo());
    }

    //计算获取出队序列,count代表报数人序号为count时出队,从1开始
    public void JossephuGame (int count) {
//        int j =0;
        Children helper = first;
        Children currentChild = first;
        while (helper.getNext() !=first) {
            helper = helper.getNext();
        }
//      while ( j != sum-1) { 也可以用此作循环条件
        System.out.println("出队child的编号为:");
        while (true) {
            for (int i = 1; i <= count - 1; i++) {
                currentChild = currentChild.getNext();
                helper = helper.getNext();
            }
//            j++;
            System.out.println(currentChild.getNo());
            currentChild = currentChild.getNext();
            helper.setNext(currentChild);
            if (currentChild == helper) {
                //此时队伍中只剩一人
                break;
            }
        }
        System.out.println(currentChild.getNo());


    }
}