约瑟夫环问题
题目:
- 据说著名犹太历史学家Josephus有过一下的故事:
在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲在一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3个人该人必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在了第16个与第31个位置,于是逃过了这场死亡游戏。
问题分析:问题中41个人排成一圈,报数每报到第三个人该人必须自杀,把41个人看成一个链表,而且是一个单向循环链表,把每个人看做一个结点,其所在位置做为数据域position,每个人知道自己的下一个人是谁,为指针域。
定义成员变量size记录剩余人数,接下来用结点的方式初始化该链表,用真实头结点方式来做,有多少人就创建多少结点,用循环方式。借助指针p遍历链表,p从第一个结点开始,即报数为1,p指针移动到第二个结点,第三个结点是要删除的结点,将其指针域指向第四个结点,第三个结点被回收,size- -,p再从第四结点开始,循环上述过程,直到size<=2时,因为剩余两人时,无法淘汰第三个人。最后返回剩余的两个结点的数据域,即幸存的人所在位置。
package DS02.动态链表;
import DS01.动态数组.ArrayList;
import DS01.动态数组.List;
//约瑟夫环问题
public class JosephusLoop {
private Node head;
private Node rear;
private int size;
public JosephusLoop(int count){
head=new Node(1,null);
rear=head;
rear.next=head;
for(int i=2;i<=count;i++){
rear.next=new Node(i,rear.next);
rear=rear.next;
}
size=count;
}
public List<Integer> getSurvivePosition(){
ArrayList<Integer> list=new ArrayList<>();
Node p=head;
while(size>2){
p=p.next;
Node del=p.next;
if(del==head){
head=head.next;
}
if(del==rear){
rear=p;
}
p.next=del.next;
p=p.next;
size--;
}
list.addLast(head.position);
list.addLast(rear.position);
return list;
}
private class Node{
int position;
Node next;
public Node(){}
public Node(int position,Node next){
this.position=position;
this.next=next;
}
}
public static void main(String[] args) {
JosephusLoop jp=new JosephusLoop(20);
List<Integer> list=jp.getSurvivePosition();
System.out.println(list);
}
}