public class Josephus {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addBoy(10);
System.out.println("环形链表:");
list.showBoy();
System.out.println("出圈顺序:");
list.getOrderedBoy(5,3,10);
}
}
class CircleSingleLinkedList{
// 创建一个first节点,当前没有编号,构建环形链表的时候赋值
private Boy first = null;
/**
* 构建成一个环形链表,n为环形链表的节点个数
* @param n
*/
public void addBoy(int n) {
// n 做一个数据校验
if (n < 1) {
System.out.println("参数有误");
return;
}
Boy curBoy = null; // 辅助指针,帮助构建环形链表
// 使用for循环来创建环形链表
for (int i = 1; i <= n; i++) {
// 根据编号,创建小孩节点
Boy tail = new Boy(i);
// 如果是第一个节点
if (i == 1) {
//头结点
first = tail;
first.nextBoy= first; // 构成环
curBoy = first; // 让curBoy指向第一个小孩
} else { //在第一个节点的基础上继续添加
curBoy.nextBoy = tail;
//尾节点指向头结点
tail.nextBoy= first;
curBoy = tail;
}
}
}
// 打印当前的环形链表
public void showBoy() {
// 判断链表是否为空
if (first == null) {
System.out.println("没有任何小孩");
return;
}
// 使用一个辅助指针完成遍历
Boy curBoy = first;
while (true) {
System.out.printf("小孩的编号 %d \n", curBoy.id);
if (curBoy.nextBoy == first) { //说明已经遍历完毕
break;
}
curBoy = curBoy.nextBoy; //curBoy后移
}
}
/**
* 出圈的顺序
* @param startId 开始的位置
* @param countNum 每次报数的个数
* @param n 总人数
*/
public void getOrderedBoy(int startId, int countNum, int n) {
// 先对数据进行校验
if (first == null || startId < 1 || startId > n) {
System.out.println("参数有误");
return;
}
// 辅助指针, 最开始指向链表的最后一个节点
Boy helper = first;
while (true) {
if (helper.nextBoy == first) {
break;
}
helper = helper.nextBoy;
}
//小孩报数前,先让 first 和 helper 移动到开始报数的位置和开始位置的前一个位置
for(int j = 0; j < startId - 1; j++) {
first = first.nextBoy;
helper = helper.nextBoy;
}
// 开始报数,从起始位置开始,到countNum - 1结束
//这里是一个循环操作,直到圈中只有一个节点
while(true) {
if(helper == first) { //说明圈中只有一个节点
break;
}
//让 first 和 helper 指针同时移动 countNum - 1
for(int j = 0; j < countNum - 1; j++) {
first = first.nextBoy;
helper = helper.nextBoy;
}
//这时first指向的节点,就是要出圈的小孩节点
System.out.printf("小孩%d出圈\n", first.id);
//这时将head指向下一次开始报数的位置,即出圈小孩的下一个小孩的位置
first = first.nextBoy;
//helper所在的小孩的nextBoy为出圈小孩的下一个小孩节点
helper.nextBoy = first;
}
System.out.printf("最后留在圈中的小孩编号%d \n", first.id);
}
}
class Boy{
public int id;
public Boy nextBoy;
public Boy(int id) {
this.id = id;
}
}
执行结果:
思路分析: