Josephu 问题为:
设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
package com.qcby.bilbil;
/**
* @author HuangHaiyang
* @date 2020/07/08
* @description: description
* @version: 1.0.0
*/
public class Josephus {
private Node head=null;
public void createList(int nums){
if (nums<1){
throw new RuntimeException("人数小于1");
}
Node currentNode=null;//游标指针
for (int i = 1; i <=nums; i++) {
Node newNode=new Node(i);
if(i==1){
head=newNode;
head.next=head;//一个人也要形成环
currentNode=head;
}else {
currentNode.next=newNode;
newNode.next=head;
currentNode=newNode;
}
}
}
public void showList(){
if(head==null){
throw new RuntimeException("空链表");
}
Node currentNode=head;
// while (currentNode.next!=head){
// System.out.println("值为"+currentNode.val);
// currentNode=currentNode.next;
// }
// System.out.println(currentNode.val);
while (true){
if (currentNode.next==head){
break;
}
currentNode=currentNode.next;
}
}
public void kill(int startNo,int countNum,int nums){
if(head==null||startNo<1||startNo>nums){
throw new RuntimeException("参数有误");
}
Node helper=head;
while (true){
if(helper.next==head){
break;
}
helper=helper.next;//事先将该指针指向环的最后一个节点
}
for (int i = 0; i < startNo-1; i++) {
head=head.next;
helper=helper.next;
}
while (true){
if(helper==head){
break;
}
for (int i = 0; i < countNum-1; i++) {
head=head.next;
helper=helper.next;
}
System.out.println(head.val);
head=head.next;
helper.next=head;
}
System.out.println(head.val);
}
public static void main(String[] args) {
Josephus josephus=new Josephus();
josephus.createList(5);
josephus.showList();
josephus.kill(1,2,5);
}
}
class Node{
public Integer val;
public Node next;
public Node() {
}
public Node(Integer val, Node next) {
this.val = val;
this.next = next;
}
public Node(Integer val) {
this.val = val;
}
@Override
public String toString() {
return "Node{" +
"val=" + val +
", next=" + next +
'}';
}
}