1. 约瑟夫问题的简介及实现思路
-
Josephu(约瑟夫、约瑟夫环)问题:
设编号1,2,…,n 的 n 个人围坐一圈,约定编号为 k (1 <= k <= n)的人从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
-
大致实现思路:
- 将所有人添加到循环链表中
- 然后由k结点起从1开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除,算法结束
-
实现图解:
-
单向循环链表的实现:
-
玩家类的实现:
public class GamePlayer { private String name; private int age; public GamePlayer(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "GamePlayer{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
2. 约瑟夫问题的代码实现:
import java.util.Scanner;
public class Josephus {
public static void main(String[] args) {
//循环链表
CircularLinkedList list = new CircularLinkedList();
//先来十个玩游戏的人
GamePlayer player1 = new GamePlayer("玩家一", 10);
GamePlayer player2 = new GamePlayer("玩家二", 11);
GamePlayer player3 = new GamePlayer("玩家三", 12);
GamePlayer player4 = new GamePlayer("玩家四", 13);
GamePlayer player5 = new GamePlayer("玩家五", 14);
GamePlayer player6 = new GamePlayer("玩家六", 15);
GamePlayer player7 = new GamePlayer("玩家七", 16);
GamePlayer player8 = new GamePlayer("玩家八", 17);
GamePlayer player9 = new GamePlayer("玩家九", 18);
GamePlayer player10 = new GamePlayer("玩家十", 19);
//把这十个人存到结点里,并加入到链表里
CircularNode node0 = new CircularNode(player1);
list.add(node0);
CircularNode node1 = new CircularNode(player2);
list.add(node1);
CircularNode node2 = new CircularNode(player3);
list.add(node2);
CircularNode node3 = new CircularNode(player4);
list.add(node3);
CircularNode node4 = new CircularNode(player5);
list.add(node4);
CircularNode node5 = new CircularNode(player6);
list.add(node5);
CircularNode node6 = new CircularNode(player7);
list.add(node6);
CircularNode node7 = new CircularNode(player8);
list.add(node7);
CircularNode node8 = new CircularNode(player9);
list.add(node8);
CircularNode node9 = new CircularNode(player10);
list.add(node9);
Scanner sc = new Scanner(System.in);
System.out.println("请输入从第几个人开始游戏...(1-10)");
int k = sc.nextInt();
System.out.println("请输入报数的数字...");
int m = sc.nextInt();
//模拟一个计数器
int count = 1;
//如果圈内还有两个人及两个人以上,那么游戏继续
while (list.getSize()!=1){
//首先求出要出列的人对应的索引
int index = (m+k-2)%list.getSize();
//根据索引拿到该索引对应的玩家信息
GamePlayer player = (GamePlayer) list.getByIndex(index).data;
//根据索引删掉此索引对应的玩家,表明他已出列
list.delByIndex(index);
System.out.println("第"+(count++)+"个玩家已出列,他是:"+player);
//修改 k 的值,下次从已出列的下一个人开始计数
k = index+1;
}
//求出最后一个出列的玩家
GamePlayer lastPlayer = (GamePlayer) list.getByIndex(0).data;
//删除最后一个玩家,表示他也已经出列
list.delByIndex(0);
System.out.println("第10个玩家已出列,他是:"+lastPlayer);
}
}