题目
*约瑟夫问题:设编号1、2、3…n的n个人围坐一圈 约定编号为k(1<=k<=n)的人开始从1报数 数到m的那个人出列,它的下一位又从1开始报数 ,数到m的那个人又出列依次类推 直到所有人出列为止 由此产生一个出队编号的序列
一、约瑟夫解决问题思想
首先我们先画图模拟下该问题:设n=5 ,k=1,m=2
我们设置5个孩子,从1开始报数 数到2下就出列
最后出队序列是:2 4 1 5 3
在这里我们使用单链表的环形链表来实现:
二、实现代码
节点类:
class Boy{
public int no;
public Boy next;
public Boy(int no) {
this.no = no;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
'}';
}
}
方法类:
class SingleNode{
public Boy first; //该节点用户创建环形链表
/**
* @param n 表示添加节孩子的个数
*/
public void addNode(int n){
if (n<1){
System.out.println("输入参数有误!");
return;
}
Boy temp=null; //辅助指针用于帮助创建环形链表
for (int i = 1; i <=n ; i++) {
Boy boy=new Boy(i);
//表示如果是第一个小孩
if (i==1){
first=boy;
first.next=first; //构成环状
temp=first; //让temp指向下一个小孩
}else {
temp.next=boy;
boy.next=first;
temp=boy;
}
}
}
//显示所有节点
public void showAllBoy(){
if (first==null){
System.out.println("环形链表为空!");
return;
}
//first指针不能动 所以需要辅助指针
Boy temp=first;
while (true){
System.out.print(temp.no+" ");
if (temp.next==first){
break;
}
temp=temp.next; //temp后移
}
}
/**
*
*
* @param startNo 表示从第几个小孩开始数
* @param count 数几下
* @param nums 小孩个数
*/
public void count(int startNo,int count,int nums){
if (first==null||startNo>nums||startNo<1){
System.out.println("输出参数有误!");
return;
}
//创建辅助指针
Boy temp=first;
//先让辅助指针指向最后一个节点
while (true){
if (temp.next==first){
break;
}
temp=temp.next;
}
//先让temp和first同时移动startNo-1次 因为first指向第一个节点
for (int i = 0; i <startNo-1 ; i++) {
first=first.next;
temp=temp.next;
}
//当小孩报数时 first指针和temp同时移动count-1次
//然后出圈
while (true){
if (temp==first){ //此时圈中只有一个人
break;
}
for (int i = 0; i <count-1 ; i++) {
first=first.next;
temp=temp.next;
}
System.out.print(first.no+" ");
//将小孩出圈
first=first.next;
temp.next=first;
}
System.out.print(first.no);
}
}
出圈过程: