一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
问题描述: 约瑟夫问题:有 N 个人围成一圈,每个人都有一个编号,编号由入圈的顺序决定,第一个入圈的人编号为 1,最后一个为 N,从第 k (1<=k<=N)个人开始报数,数到 m (1<=m<=N)的人将出圈,然后下一个人继续从 1 开始报数,直至所有人全部出圈,求依次出圈的编号。
思路分析
根据问题描述 可以讲每个人看成一个节点,上一个人指向下一个人,最后一个指向第一个,如此构建一个环形链表,假如有五个人,构建的环形链表如下:
出队列 当 重k开始的 数m下之后 出队列 只需要将那个节点的上一个节点的指针指向这个节点的下一个节点
代码实现
- 构建节点类
class JosephusNode{
int number;
JosephusNode next;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public JosephusNode getNext() {
return next;
}
public void setNext(JosephusNode next) {
this.next = next;
}
@Override
public String toString() {
return "JosephusNode{" +
"number=" + number +
", next=" + next +
'}';
}
2.创建环形链表方法
public static JosephusNode createNodes(int size){
//头节点
JosephusNode josephusNode = new JosephusNode();
//虚拟指针指向最后一个节点
JosephusNode tail = josephusNode;
//虚拟指针指向最后一个节点
JosephusNode head = josephusNode;
for (int i = 0; i <size ; i++) {
if(i+1 ==size){
tail.setNext(head);
continue;
}
JosephusNode josephusNodeNext = new JosephusNode();
josephusNodeNext.setNumber(i+1);
//链接在最后一个节点后面
tail.setNext(josephusNodeNext);
tail = josephusNodeNext;
}
return josephusNode;
}
3.出队列
public static void outOfTheTeam(JosephusNode nodes,int k,int m){
JosephusNode curNode = nodes;
JosephusNode curNodeLast = nodes;
//指向第k个节点
for (int i = 0; i < k-1; i++) {
curNode = curNode.getNext();
}
//指向第k个节点的前一个节点
for (;;) {
if(curNodeLast.getNext() == curNode){
break;
}
curNodeLast = curNodeLast.getNext();
}
int count =1;
while (true){
if(curNode.getNumber()==curNode.getNext().getNumber()){
System.out.println(curNode.getNext().getNumber());
break;
}
if(count == m){
count =0;
//出圈
System.out.println(curNode.getNumber());
//将当前节点的下一个节点 赋值给curNodeLast的下一个节点 完成出圈
JosephusNode curNodeDeleteNext = curNode.getNext();
curNodeLast.setNext(curNodeDeleteNext);
curNode = curNodeLast.getNext();
// curNode.getNext().setNext(null);
}else{
//不出圈都往后移
curNode= curNode.getNext();
curNodeLast= curNodeLast.getNext();
}
count ++;
}
}
测试结果如下(我的节点是以0开头的):
3 7 4 1 0 2 6 5