构建一个单向的环形链表:
1. 先创建第一个结点, 让 first 指向该结点,并形成环形
2. 后面当我们每创建一个新的结点,就把该结点,加入到已有的环形链表中即可.
遍历环形链表:
1. 先让一个辅助指针(变量) temp,指向first结点
2. 然后通过一个while循环遍历 该环形链表即可 temp.getNext() == first 结束
小孩出圈:
1. 创建一个辅助指针(变量) temp, 事先应该指向环形链表的最后这个结点
小孩报数前,先让 first 和 temp 移动 k-1次
2. 当小孩报数时,让 first 和 helper 指针同时移动 m-1 次(自己要数一下)
3. 这时就可以将 first 指向的小孩结点出圈
first = first.getNext();
temp.setNext(first);
原来first 指向的结点就没有任何引用,就会被回收
public class Josephus {
public static void main(String[] args) {
CircleSingleLinkedList csll = new CircleSingleLinkedList();
csll.add(5);
csll.display();
csll.out(1, 2, 5);
}
}
// 创建一个环形单向链表
class CircleSingleLinkedList {
// 创建一个first结点,当前没有编号
private Boy first = null;
// 添加结点,构成一个环形链表
public void add(int nums) {
// 对nums进行校验
if (nums < 1) {
System.out.println("nums的值不合法!");
return;
}
// 辅助结点,帮助构建环形链表
Boy temp = null;
for (int i = 1; i <= nums; i++) {
// 创建Boy结点
Boy boy = new Boy(i);
// 创建第一个结点的时候
if (i == 1) {
// 把第一个创建的结点作为first结点
first = boy;
// 第一个结点指向自身,构成环状
first.setNext(first);
// temp指向第一个结点
temp = first;
} else {
// 辅助结点指向新建结点
temp.setNext(boy);
// 新建结点指向first结点
boy.setNext(first);
// temp结点后移
temp = boy;
}
}
}
// 遍历当前环形列表
public void display() {
if (first == null) {
System.out.println("链表为空!");
return;
}
// 因为first不能动,使用辅助结点
Boy temp = first;
while (temp.getNext() != first) {
System.out.println("结点的编号是:" + temp.getNo());
// temp结点后移
temp = temp.getNext();
}
}
/**
* 根据用户的输入,进行出圈的操作
* @param startNo 从第几个开始数数
* @param countNo 数几下
* @param nums 圈中最初的结点数
*/
public void out(int startNo, int countNo, int nums) {
// 数据校验
if (first == null || startNo < 1 || startNo > nums) {
System.out.println("输入的参数不合法!");
return;
}
// 创建一个辅助结点,事先位于环形链表最后的位置,此时,temp位于first的前一位
Boy temp = first;
while (temp.getNext() != first) {
temp = temp.getNext();
}
// 小孩报数前,为了确保报数的第一个小孩始终是first,先让first和temp移动k-1次,此时,temp位于first的前一位
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
temp = temp.getNext();
}
// 出圈操作,让first和helper指针同时移动m-1次,确保出圈的小孩是first
while (temp != first) {
for (int j = 0; j < countNo - 1; j++) {
first = first.getNext();
temp = temp.getNext();
}
// 这时,让first指向的小孩出圈
System.out.println("小孩" + first.getNo()+ "出圈!");
first = first.getNext();
temp.setNext(first);
}
System.out.println("最后留在圈中的小孩编号是:" + first.getNo());
}
}
// 创建一个Boy类,表示一个结点
class Boy {
private int no;
private Boy next;
public Boy(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
}