问题描述
约瑟夫环问题起源于一个犹太故事。约瑟夫环问题的大意如下罗马人攻占了桥塔帕特,41个人藏在一个山洞中躲过了这场浩劫。这41个人中,包括历史学家约瑟夫和他的一个朋友。剩余的39个人为了表示不向罗马人屈服,决定集体自杀。大家决定了一个自杀方案,所有这41个人围成一个圆圈,由第1个人开始顺时针报数,每报数为3的人就立刻自杀,然后再由下一个人继续报数,仍然是每报数为3的人就立刻自杀……,直到所有人都自杀身亡为止。约瑟夫和他的朋友并不想自杀,于是约瑟夫想到了一个计策,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
解题思路
1.构建含有41个结点的单向循环链表,分别储存1-41的值,分别代表这41个人;
2.使用计数器count,记录当前报数的值;
3.遍历链表,每循环一次,count++;
4.判断count值,如果是3,则从链表中删除这个结点并打印结点的值,把count重置为0;
1.构建循环链表
//1.构建循环链表,包含41个结点,分别储存1-41之间的值
Node<Integer> first=null; //首结点
Node<Integer> pre=null; //记录前一个结点
for(int i=1;i<42;i++){
//如果是第一个结点
if(i==1){
first=new Node<>(i,null);
pre=first;
continue;
}
//如果不是第一个结点
Node<Integer> newNode = new Node<>(i, null);
pre.next=newNode;
pre=newNode;
//如果是最后一个结点,那么需要最后一个结点的下一个结点指向first,变为循环链表
if(i==41){
pre.next=first;
}
}
2.遍历循环链表
//2.需要count计数器,模拟报数
int count=0;
//3.遍历循环链表
Node<Integer> n=first;
Node<Integer> pre2=null;
while(n!=n.next){
//模拟报数
count++;
if(count==3){
//删除当前节点
pre2.next=n.next;
System.out.print(n.data+",");
count=0;
n=n.next;
}else{
pre2=n;
n=n.next;
}
}
//打印最后一个元素
System.out.println(n.data);
}
3.完整代码
package cn.itcast.algorithm.linearTest;
public class JosephTest {
public static void main(String[] args) {
//解决约瑟夫问题
//1.构建循环链表,包含41个结点,分别储存1-41之间的值
Node<Integer> first=null; //首结点
Node<Integer> pre=null; //记录前一个结点
for(int i=1;i<42;i++){
//如果是第一个结点
if(i==1){
first=new Node<>(i,null);
pre=first;
continue;
}
//如果不是第一个结点
Node<Integer> newNode = new Node<>(i, null);
pre.next=newNode;
pre=newNode;
//如果是最后一个结点,那么需要最后一个结点的下一个结点指向first,变为循环链表
if(i==41){
pre.next=first;
}
}
//2.需要count计数器,模拟报数
int count=0;
//3.遍历循环链表
Node<Integer> n=first;
Node<Integer> pre2=null;
while(n!=n.next){
//模拟报数
count++;
if(count==3){
//删除当前节点
pre2.next=n.next;
System.out.print(n.data+",");
count=0;
n=n.next;
}else{
pre2=n;
n=n.next;
}
}
//打印最后一个元素
System.out.println(n.data);
}
//结点类
public static class Node<T>{
private T data;
private Node next;
public Node(T data,Node next){
this.data=data;
this.next=next;
}
}
}
4.测试结果
可以发现最后两个数是16和31,所以约瑟夫和他的朋友逃过一劫。