目录
一、约瑟夫问题介绍
设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
二、约瑟夫问题算法介绍
1.首先构建一个单向的环形链表
①先创建第一个节点, 让 first 指向该节点,并形成环形
②后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表中即可.
2.按照需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点.
补充: 小孩报数前,先让 first 和helper 移动 k - 1次
3.当小孩报数时,让first 和 helper 指针同时的移动 m - 1 次
4.这时就可以将first 指向的小孩节点出圈
first = first .next
helper.next = first
原来first 指向的节点就没有任何引用,就会被回收
三、约瑟夫问题代码实现
public class Josepfu {
public static void main(String[] args){
SingleCircleList singleCircleList=new SingleCircleList();
singleCircleList.countBoy(1,2,5);
}
}
class SingleCircleList{
private Boy first=null;
// 构造循环单链表
public void addBoy(int nums){
if(nums<1){
System.out.println("nums输入有误!");
return;
}
// 临时指针,用来添加结点
Boy curBoy=null;
// 添加结点过程
for (int j=1;j<=nums;j++){
Boy body=new Boy(j);
// 将第一个结点构成环
if(j==1){
first=body;
body.setNext(first);
curBoy=first;
}else {
// 添加结点
curBoy.setNext(body);
body.setNext(first);
curBoy=body;
}
}
}
// 遍历循环单链表
public void showBoy(){
if (first==null){
System.out.println("没有任何小孩!");
return;
}
// 使用curBoy来指向最开始的节点
Boy curBoy=first;
// 对循环单链表进行遍历
while (true){
System.out.println("小孩编号为:"+curBoy.getNo());
// 判断是否遍历到最后
if(curBoy.getNext()==first){
break;
}
curBoy=curBoy.getNext();
}
}
// 解决约瑟夫问题
// k为约定编号
// m为报数个数
// n为圈人数
public void countBoy(int k,int m,int n){
// 构造n个环形单链表
addBoy(n);
// 用来指向单链表的最后一个结点
Boy helper=first;
// 实现helper指向单链表的最后一个结点
while (true){
if (helper.getNext()==first){
break;
}
helper=helper.getNext();
}
// 从第k个开始数
for (int j=0;j<k-1;j++){
first=first.getNext();
helper=helper.getNext();
}
while (true){
if(helper==first){
System.out.println("最后一个小孩编号为:"+helper.getNo());
break;
}
for (int j=0;j<m-1;j++){
first=first.getNext();
helper=helper.getNext();
}
System.out.println("小孩编号:"+first.getNo());
first=first.getNext();
helper.setNext(first);
}
}
}
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;
}
}