约瑟夫问题:
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?
使用环形链表来解决这个问题
首先构建和显示环形链表
class CircleSingleLinkedList {
//创建一个first节点,当前没有编号
private Person first = null;
//添加人节点,构成一个环形链表
public void addPerson(int nums) {
if (nums < 1) {
System.out.println("nums值不正确");
return;
}
//定义一个辅助指针,帮助构建环形链表
Person curP = null;
for(int i=1;i<=nums;i++){
Person person = new Person(i);
if(i == 1){
first = person;
first.setNext(first);
curP = first;
}else{
curP.setNext(person);
person.setNext(first);
curP = person;
}
}
}
public void show(){
if(first == null){
System.out.println("没人");
return;
}
Person cur = first;
while(true){
System.out.println("编号:"+cur.getNo());
if(cur.getNext() == first){//遍历完毕 退出
break;
}
cur = cur.getNext();//后移
}
}
}
class Person {
private int no;
private Person next;
public Person(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Person getNext() {
return next;
}
public void setNext(Person next) {
this.next = next;
}
}
计算出圈顺序的方法
/**
* @param startNo 从第几个人开始数
* @param countNum 每次数几下
* @param nums 最初有多少个人在圈中
*/
public void countPerson(int startNo,int countNum,int nums){
if(first == null || startNo < 1 || countNum > nums){
System.out.println("输入的数据不合法");
return;
}
//使用一个辅助节点指针,并让他指向这个环形链表的最后一个节点
Person helper = first;
while(true){
if(helper.getNext() == first){
break;
}
helper = helper.getNext();
}
//人报数前,先把开始节点和辅助节点移动到startNo的位置,即让first和helper移动startNo-1次
for(int i=0;i<startNo-1;i++){
first = first.getNext();
helper = helper.getNext();
}
//人报数时,让first和helper同时移动countNum-1次,然后出圈
while(true){
if(first == helper){//说明圈中只有一个节点
break;
}
for(int i=0;i<countNum-1;i++){
first = first.getNext();
helper = helper.getNext();
}
//此时first指向的节点就是要出圈的人
System.out.println("编号"+first.getNo()+"出圈");
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后留在圈中的人的编号是"+first.getNo());
}
自己根据代码画图会比较容易理解