前言
Josephu、单向环形链表假设你已经会Java基础、链表
一、Josephu问题是什么?
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列二、思路
1.分析问题
- n个人围坐成一圈:可以通过创建一个不带头结点、n个节点的单向环形链表(单向环形链表:尾节点的next指向头节点 )
- 约定编号为k的人从1开始报数: 头结点到k位置时开始
- 数到m出列: 头结点移动到m时移除节点
2.创建链表思路
- 构建单向环形链表:当创建第一个节点head时,要让head的next指向自己,形成环形(一个节点也是环形)
- 创建节点
代码如下(示例):
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;
}
}
- 加入节点时,head节点的next指向新节点,并让新结点的next指向head
代码如下(示例):
// 借助辅助指针 当前最后节点
Boy curBoy = null;
// 要nums个节点
for (int i = 1; i <= nums; i++) {
Boy boy = new Boy(i);
if (i == 1){
head = boy;
head.setNext(first);
curBoy = head;
}else{
curBoy.setNext(boy);
boy.setNext(head);
curBoy = curBoy.getNext();
}
}
- 遍历时,当尾结点的next == head时,说明遍历完成
代码如下(示例):
if (head == null){
System.out.println("空");
return;
}
Boy curBoy = first;
while(true){
System.out.println(curBoy.getNo());
if (curBoy.getNext() == head){
break;
}
curBoy = curBoy.getNext();
}
3.小孩出圈思路(Josepfu)
- 假设用户输入,生成一个出圈顺序:
- n = 5,即有5个小孩
- k = 1,从1开始报数
- m = 2,报到2出列
- 出列顺序为 2->4->1->5->3
- 创建一个helperBoy指向尾节点,同时我们有head节点指向头节点,在开始之前,要把头尾指针移动 k-1次
- 当小孩报数时,要让helperBoy、head移动 m-1次
- 这是把first指向的节点出列
代码如下(示例):
head = head.next
helperBoy.next = head
- 没有引用的节点 就会被gc回收
4.代码实现
代码如下(示例):
/**
*
* @param startNo 第几个小孩开始数
* @param countNum 数几下
* @param nums 最初有多少小孩在圈中
*/
public void countBoy(int startNo, int countNum, int nums){
if (startNo < 1 || countNum < 1 || startNo > nums){
System.out.println("error");
return;
}
// 先移动 头节点
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
}
// 尾节点
Boy helperBoy = first;
while (true) {
if (helperBoy.getNext() == first){
break;
}
helperBoy = helperBoy.getNext();
}
while(true){
// 圈中只有一个节点 退出循环
if (helperBoy == first){
break;
}
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helperBoy = helperBoy.getNext();
}
System.out.println("出圈" + first.getNo());
first = first.getNext();
helperBoy.setNext(first);
}
System.out.println("最后的小孩" + first.getNo());
}
}