约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。 如此反复,最后剩下一个,求最后的胜利者。 例如只有三个人,把他们叫做A、B、C,他们围成一圈,从A开始报数,假设报2的人被杀掉。
约瑟夫问题其实就一个循环链表问题
先创建节点类
public class Node {
private int no;
private Node next; //指向下一个节点
public Node(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
加入节点操作
使用一个辅助节点指向当前链表的最后一个节点,加入节点的操作就是将当前节点的next域指向加入的节点,将加入节点的next域指向第一个节点,同时要将辅助节点向后移一个位置
package com.ht.circlelinkedlist;
/**
* @author ht
* @create 2020-10-29 18:59
* @description
*/
public class CircleSingleLinkedList {
//创建一个first节点,没有编号
private Node first = null;
//加入节点,nums为加入节点个数
public void addNode(int nums){
//做nums进行数据校验
if(nums < 1){
System.out.println("nums值不正确");
return;
}
Node curNode = null;
for(int i = 1; i <= nums; i++){
//根据编号,创建节点
Node node = new Node(i);
if(i == 1){
first = node;
first.setNext(first);
curNode = first;
}else{
curNode.setNext(node);
node.setNext(first);
curNode = node;
}
}
}
遍历链表就是使用辅助节点进行遍历,和普通链表的遍历是一样的
//遍历链表
public void showNode(){
if(first == null){
System.out.println("链表为空,遍历失败");
return;
}
Node curNode = first;
while(true){
System.out.println(curNode.getNo());
if(curNode.getNext() == first){
break;
}
curNode = curNode.getNext();
}
}
约瑟夫问题的解决
代码中有注释,够看
/**
*
* @param startNo 开始报数
* @param countNum 数几下
* @param nums 总数
*/
public void countNode(int startNo, int countNum, int nums){
if(first == null || startNo < 1 || startNo > nums || countNum > nums){
System.out.println("数据有误,请检验");
return;
}
//创建辅助指针,帮助出圈
Node helper = first;
//事先让辅助节点指向最后一个节点
while(true){
if(helper.getNext() == first){
break;
}
helper = helper.getNext();
}
//报数前,让first和helper移到相应节点
for(int j = 0; j < startNo - 1; j++){
first = first.getNext();
helper = helper.getNext();
}
while(true){
if(helper == first){ //说明当时圈中只有一个节点
break;
}
//让first和helper移动countNum - 1
for(int i = 0; i < countNum - 1; i++){
first = first.getNext();
helper = helper.getNext();
}
System.out.println("节点" + first.getNo() + "出圈");
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后留在圈中的节点是" + first.getNo());
}
}