版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/yanglong_blog_/article/details/76387982
问题后面的小故事:
公元66年,约瑟夫参与领导了犹太同胞反抗罗马统治的起义,起义失败,他和一些宁死不降的起义者被困于一个山洞之中。罗马将军派人来劝降,他主张投降,其余的人不答应,并以死相逼。最后,约瑟夫提议,与其死在自己的手上,不如死在彼此的手上。他提出了从第一个人开始,每数到三,则第三个人自杀,从下一个人开始继续从1开始数,每数到三,则第三个人继续自杀…..直到所有人都死亡为之,就这样执行下去,最后只有他和另外一人出了山洞投降。这个问题被后来人们称为约瑟夫环.
求解思路:
采用单向循环链表,每个人代表一个结点,假设1号是头结点,从头结点开始数,数到3,则先打印第3个人的编号,继续向下数,直到所有的结点都被遍历一遍,循环结束。
输入输出描述:
假设输入 n 个人, 数到第 m 个人,删除第m个人,
如 n = 41, m = 3, 则删除顺序为 3 -> 6 -> 9 -> 12 -> 15…..
结点代码:
public class Node {
int c;
Node next;
public Node() {
}
public Node(int c, Node next) {
super();
this.c = c;
this.next = next;
}
}
主函数代码:
/*
* @Description: 求解约瑟夫环
* 假设有 n 个结点,从第一个结点开始数,每数到m,第m个人 * 出列(这里就先打印第m个结点的值,再删除m结点)
* 使用单向循环链表
* 最后输出被删除的先后顺序,即m的删除顺序
*/
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n; // 结点个数
int m; // 第m出列
System.out.print("Input N and M:");
n = sc.nextInt();
m = sc.nextInt();
//声明n个结点
Node[] node = new Node[n];
//为每个结点赋值
for(int i=0; i<node.length; i++){
node[i] = new Node(i+1, null);
}
//将第一个结点指向下一个结点
for(int i=0; i<node.length-1; i++){
node[i].next = node[i+1];
}
//将最后一个结点指向第一个结点,构成一个环
node[node.length-1].next = node[0];
//先将p指向第一个结点, p在以后表示要删除结点的前驱结点
Node p = node[0];
int k = 0; //控制输入的一行的个数
// 只要还有结点,就继续循环,即结点p自己指向自己,循环结束
while(p.next != p ){
//找到被删除结点的前驱结点
for(int i=0; i<m-2; i++){
p = p.next;
}
//每输出6个元素输出一个换行
if (k % 6 == 0){
System.out.format("\n %02d - ", p.next.c);
}else{
System.out.format(" %02d - ", p.next.c);
}
k++;
//删除 p的后继结点, 即被出列的结点
Node s = p.next;
p.next = s.next;
s.next = null;
//最后使p指向开始数的第一个结点,即被删除结点的下一结点
p = p.next;
}
//输出最后一个结点
System.out.format(" %02d", p.c);
sc.close();//关闭输入流
}
}
运行效果图:
源码下载:
约瑟夫环源码下载(点击我即可下载)