约瑟夫问题为:设编号为1,2,……n得n个人围坐一圈,约定编号为k(k大于等于1并且小于等于n)的人从1开始报数,数到m的那个人出列。它的下一位继续从1开始报数,数到m的人出列,依次类推,直到所有人都出列为止。
1.定义Node类
class Node{
public int no;//编号
public Node next;//下一个节点
public Node(int no){
this.no = no;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
'}';
}
}
2.定义CircleLinkedList类
class CircleLinkedList{
public Node first;//第一个节点
//构造方法
public CircleLinkedList(Node first) {
this.first = first;
first.next = first;
}
/**
* 添加节点 每次都是将节点插入first节点和其之前的节点之间
* @param insertNode 插入的节点
*/
public void add(Node insertNode){
Node temp = first;
//寻找first之前的节点,即如果发现temp的下一个节点是first就结束循环
while (temp.next != first){
temp = temp.next;
}
//这里的temp是first之前的节点
temp.next = insertNode;
insertNode.next = first;
}
}
3.定义CircleLinkedListDemo类
public class CircleLinkedListDemo {
public static void main(String[] args) {
//约瑟夫问题
Scanner scanner = new Scanner(System.in);
System.out.println("请输入n(人数):");
int n = scanner.nextInt();
System.out.println("请输入k(从第几个开始报数):");
int k = scanner.nextInt();
System.out.println("请输入m(数几个):");
int m = scanner.nextInt();
//1.根据n创建循环链表
CircleLinkedList list = new CircleLinkedList(new Node(1));
for (int i = 2; i < n+1; i++) {
list.add(new Node(i));
}
//2.定位到第一个数数的人。以及temp之前的节点(为了删除节点)
Node temp = list.first;
Node tempLast = list.first;
for (int i = 1; i < k; i++){
tempLast = temp;
temp = temp.next;
}
//3.开始数数,删除出队列的人节点
int countN = 0;//记录出队列的人数,当count==n即结束while循环
int countM = 1;//记录数数的数字
while (countN != n) {
//一、每一轮循环开始之前先进行判断:
// 1.判断是否出队列人数已满(countN == n) 2.此节点是否符合出队列的要求(countM == m)
if (countM == m) {
//删除此节点,输出此节点的编号,并且将countM=0
System.out.print(temp.no + "->");
tempLast.next = temp.next;
countN++;
countM = 0;
}
//二、将temp的值变成下一个节点,然后进行countM++
tempLast = temp;
temp = temp.next;
countM++;
}
}
}