单向环形链表解决约瑟夫环(Josephus)问题

时间:2023-11-28 14:15:20

一、约瑟夫环问题

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

二、解决思路

​ 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。

三、实现代码

1.需要的数据结构

节点

class Boy{
private int no;//编号
private Boy next;
public Boy(int no){
this.no=no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
}

单向环形链表

class CircleList{

    private Boy first = null;

    /**
*
* @param startNo 从第几个小孩开始数
* @param countNo 每次数几下
* @param nums 小孩的数量
*/
public void outOfCircle(int startNo, int countNo,int nums){
if (first==null || startNo<1|| startNo>nums){
System.out.println("参数输入有误");
return;
}
//创建辅助指针helper即要出圈小孩的前一个节点
Boy helper = first;
while (true){
if (helper.getNext()==first){
break;//helper已经到达first前的节点
}
helper=helper.getNext();
}
//移动到开始报数的位置
for (int i = 0; i <startNo-1 ; i++) {
first = first.getNext();
helper =helper.getNext();
}
//开始报数
while(true){
if(helper == first){//只有一个节点
break;
}
for (int i = 0; i <countNo-1 ; i++) {
//1、寻找待出圈的小孩、循环完成时,first就是要出圈的小孩
first = first.getNext();
helper =helper.getNext();
}
System.out.printf("出圈小孩编号:%d\n",first.getNo());
helper.setNext(first.getNext());
first=first.getNext();
}
System.out.printf("最后留在圈中的小孩编号:%d\n",first.getNo());
} public void addBoy(int nums){
if (nums<1){
System.out.println("数量有误");
return;
}
Boy curBoy =null;
for (int i = 0; i < nums; i++) {
Boy boy =new Boy(i+1);
//如果是第一个小孩,指向本身
if (i==0){
first=boy;
first.setNext(first);
curBoy=first;
}else{
curBoy.setNext(boy);
boy.setNext(first);
curBoy=boy;
}
}
} public void display(){
if (first==null){
System.out.println("链表为空");
return;
}
Boy curBoy = first;
while(true){
System.out.printf("小孩的编号:%d\n",curBoy.getNo());
if (curBoy.getNext()==first){
break;
}
curBoy=curBoy.getNext();//后移
}
}
}
2.测试代码与结果

测试类

public class Josepfu {

    public static void main(String[] args) {
CircleList c = new CircleList();
c.addBoy(5);
c.outOfCircle(1,2,5);
} }

运行结果

单向环形链表解决约瑟夫环(Josephus)问题