约瑟夫问题,是一个计算机科学和数学中的问题,在计算机编程的算法中,类似问题又称为约瑟夫环,又称“丢手绢问题”。
-百度百科
相信大部分人在刚开始接触Java算法都会遇到约瑟夫问题,约瑟夫问题可以这样理解:
有n个小孩围成一圈,给他们从1开始依次编号,从编号为1的小孩开始报数,数到第m个小孩出列,然后从出列的下一个小孩重新开始报数,数到第m个小孩又出列,…,如此反复直到所有的小孩全部出列为止,求整个出列序列。
用Java算法求解约瑟夫问题,此处用到的是循环单链表模式
代码如下:
public class Joseph { //求解约瑟夫问题类
int n, m;
Child firstChild; //首结点的指针
public Joseph(int n1, int m1) { //构造方法,建立有n1个结点的循环单链表
Child p, t; //这里的t指向新建循环单链表的尾结点
n = n1; //设置数据成员值
m = m1; //设置数据成员值
firstChild = new Child(1); //首先简历no为1的首结点
t = firstChild;
if (n < 1) { //如果输入的小孩个数不符合常理,那么应该向用户报错
System.out.println("输入数据错误!");
return;
}
for (int i = 2; i <= n; i++) {
p = new Child(i); //建立一个编号为i的新结点p
t.next = p; //将p结点链到末尾
t = p;
}
t.next = firstChild; //构成一个首结点为firstChild的循环单链表
}
public String Jesquence() { //求解约瑟夫序列
String answer = " ";
int i, j;
Child p, q;
for (i = 1; i <= n; i++) { //共列出有n个小孩
p = firstChild;
j = 1;
while (j < (m - 1)) { //报到第m-1个结点结束
j++; //报数递增
p = p.next; //找到下一个结点
}
q = p.next; //让q指向第m个结点
answer += q.no + " "; //该结点的小孩出列并输出该小孩的编号
p.next = q.next; //删除q结点
firstChild = p.next; //从下一结点重新开始
}
return answer;
}
}
class Child { //首先小孩结点类型
int no; //每个小孩的编号
Child next; //指向下一个结点的指针
public Child(int no1) { //重载构造方法
no = no1;
next = null;
}
}
那么我们可以开始写测试类了:
public class JosephTest { //约瑟夫问题的测试类
public static void main(String[] args) {
int n = 6, m = 3;
Joseph joseph1 = new Joseph(n, m);
System.out.println("n=" + n + ", m=" + m + "的约瑟夫序列为:" + joseph1.Jesquence());
n = 8;
m = 4;
Joseph joseph2 = new Joseph(n, m);
System.out.println("n=" + n + ", m=" + m + "的约瑟夫序列为:" + joseph2.Jesquence());
}
}
输出结果如下: