约瑟夫(Josephus)问题——通过循环链表解决

1、问题描述

**设编号为1,2,……,n(n>0)的n 个人按顺时针方向围坐一个圆圈,从第1 个人开始顺时针方向自1起顺序报数,报数到 m 为止,报数为 m 的人出列,然后从他的下一个人开始重新报数,报数为 m 的人又出列,……,直到所有的人全部出列为止。设计算法求n个人出圈的次序。

2、基本要求

(1)采用不带头结点的循环链表作为存储结构。
(2)对任意n个人,密码m,实现约瑟夫问题。
(3)出圈人员的编号依次输出。

=============================================================

思路

  1. 根据对应的人数创建对应的循环链表,其实循环链表只需在其最后那个节点的下一个节点在指向头结点的下一个节点即可,这样便可以去掉头结点
    约瑟夫(Josephus)问题——通过循环链表解决_第1张图片
  2. 根据循环的次数来拿出对应的序号,同时删除对应在链表中存在的序号(即指向下一个的再下一个即可)

代码如下

1.创建Node类

public class Node {
    public Object data;//存放结点值

    public Node next;//后继结点的引用

    //无参数的构造函数
    public Node(){
        this(null,null);
    }

    //带一个参数时的构造函数
    public Node(Object data){
        this(data,null);
    }

    //带两个参数时的构造函数
    public Node(Object data,Node next){
        this.data=data;
        this.next=next;
    }
}
  1. 创建对应的方法
public class Johephus {
    private Node head;
    //初始化人员的数量
    private int n;
    //初始化出圈的次序
    private int m;

    public Johephus(int n,int m){
        this.m=m;
        this.n=n;
        head = new Node();
        int num=0;
        for(int i=0;i<n;i++){
            insert(i,++num);
        }
    }

    public void insert(int i,Object x){
        Node p = head;//初始化p指向头结点
        int j=-1;
        while(p!=null&&j<i-1){
            p=p.next;
            ++j;
        }
        if(j>i-1||p==null)
            System.out.println("插入位置不合法");

        Node s = new Node(x);
        s.next=p.next;
        p.next=s;
        /**
         * 当插入到最后一个人时,该人的下一个结点又回到第一个人那,形成循环链表
         */
        if(i==n-1){
            p.next.next=head.next;
        }
    }

    public void Sequence(){
        int[] seq = new int[n];//设置数组,用于存放出圈的人的对应序号
        int len = n ;//设置出圈人数,但减为0时表示出圈结束
        int i=0;//表示指数,但加到4表示一个循环出一个人
        int index=0;//出圈人对应的下标
        Node p = head.next;
        while(len!=0){
            while(i!=m-2){//但出圈到第三次时便要跳出循环,下一个便是要取出的人对应的序号
                p=p.next;
                i++;
            }
            //跳出循环,表示p的下一个结点即是要跳出循环的人对应的序号
            seq[index]= (int) p.next.data;//将对应的序号存入数组中
            p.next=p.next.next;//并将该出圈的人移除该链表,既p的下一个结点指向已跳出循环的结点的再下一个结点
            p=p.next;//使p指向下一个结点
            i=0;//使i归零,重新下一个循环
            index++;//数组的指针加一
            len--;//链表结点减一
        }
        //最后一一输入出圈人对应的序号即可
        for(int a:seq){
            System.out.println(a);
        }
    }
}
  1. 创建测试类完成测试
 public class JohephusTest {
    public static void main(String[] args) {
        Johephus johephus = new Johephus(6,3);
        johephus.Sequence();
    }
}

你可能感兴趣的:(数据结构与算法)