问题描述
经典的约瑟夫环问题为,一群小孩子手拉手围成一圈,然后指定某个小孩从1开始报数,直到报到M的小孩子出圈,然后下一个位置的孩子继续从1开始报数。游戏结束为圈中只剩下一个孩子。
主要思路
可以考虑通过使用循环单向链表来模拟该游戏的整个过程,解决该问题。
创建结点类
结点类主要包括结点的编号 no 属性和 Next 指针域
//Node class
class Node{
public int no;
public Node next; //next
//constructor function
public Node(int no){
this.no = no;
}
}
创建循环单向链表类
循环单向链表采用无头结点的单向链表构建方式,属性包括头结点,成员方法包括创建结点围成的圈,遍历圈中所有结点,模拟结点出圈
成员方法介绍
1、createCircle(): 通过设置圈中结点个数来创建圈,使用辅助指针指向链表的最后位置,每次加入结点时使用辅助指针来完成
public void createCircle(int totalNums){
if(totalNums < 1){
System.out.println("can create Circle.");
return;
}
Node lastNode = null; //helper node to record last node position.
for(int i = 1; i <= totalNums; i++){
Node curNode = new Node(i);
//The first node.
if(i == 1){
first = curNode;
first.next = first;
lastNode = first;
}else{
lastNode.next = curNode;
curNode.next = first;
lastNode = curNode;
}
}
}
2、visitCircle(): 使用辅助指针,依次遍历整个链表,直到访问到最后位置的结点退出
public void visitCircle(){
if(first == null){
System.out.println("Circle is empty.");
return;
}
Node tmpNode = first;
while(true){
System.out.println("curNode Number: " + tmpNode.no);
if(tmpNode.next == first){
break;
}
tmpNode = tmpNode.next;
}
}
3、outCircle(): 模拟出圈过程,首先定义辅助指针 lastNode 用于指向链表的最后位置辅助出圈,第一步将辅助指针移动到链表尾部位置,第二步将 first 指针和 lastNode 指针移动到报数的起始位置,第三步循环,然后将first 指针和 lastNode 指针移动报数步找到要出圈的结点,将其出圈,直到最终链表中只剩下一个结点为止
public void outCircle(int startNo, int countNum, int totalNums){
if(first == null || startNo < 1 || startNo > totalNums){
System.out.println("Can not start the game.");
return;
}
Node lastNode = first; // record last node position.
//1、首先将lastNode移动到当前链表的最后位置
while(true){
if(lastNode.next == first){
break;
}
lastNode = lastNode.next;
}
//2、将first和辅助指针同时向后移动startNo-1位置到达开始报数的起始位置
for(int i = 1; i < startNo; i++){
first = first.next;
lastNode = lastNode.next;
}
//3、将first和辅助指针同时向后移动countNum - 1位置,使当前位置结点出圈,使用循环直到圈中只还有一个结点
while(true){
// Only one node left in the circle.
if(lastNode == first){
break;
}
for(int i = 1; i < countNum; i++){
first = first.next;
lastNode = lastNode.next;
}
// delete curNode from circle.
System.out.print(first.no + " -> ");
first = first.next;
lastNode.next = first;
}
System.out.print("LastNode:" + first.no);
}
完整代码
import java.io.*;
import java.util.*;
//Author:Peiliang Gong
//DataStructure:[Josephu implemented by CircleSingleLinkedList]
//Node class
class Node{
public int no;
public Node next; //next
//constructor function
public Node(int no){
this.no = no;
}
}
class CircleSingleLinkedList
{
public Node first = null;
public void createCircle(int totalNums){
if(totalNums < 1){
System.out.println("can create Circle.");
return;
}
Node lastNode = null; //helper node to record last node position.
for(int i = 1; i <= totalNums; i++){
Node curNode = new Node(i);
//The first node.
if(i == 1){
first = curNode;
first.next = first;
lastNode = first;
}else{
lastNode.next = curNode;
curNode.next = first;
lastNode = curNode;
}
}
}
public void visitCircle(){
if(first == null){
System.out.println("Circle is empty.");
return;
}
Node tmpNode = first;
while(true){
System.out.println("curNode Number: " + tmpNode.no);
if(tmpNode.next == first){
break;
}
tmpNode = tmpNode.next;
}
}
public void outCircle(int startNo, int countNum, int totalNums){
if(first == null || startNo < 1 || startNo > totalNums){
System.out.println("Can not start the game.");
return;
}
Node lastNode = first; // record last node position.
//1、首先将lastNode移动到当前链表的最后位置
while(true){
if(lastNode.next == first){
break;
}
lastNode = lastNode.next;
}
//2、将first和辅助指针同时向后移动startNo-1位置到达开始报数的起始位置
for(int i = 1; i < startNo; i++){
first = first.next;
lastNode = lastNode.next;
}
//3、将first和辅助指针同时向后移动countNum - 1位置,使当前位置结点出圈,使用循环直到圈中只还有一个结点
while(true){
// Only one node left in the circle.
if(lastNode == first){
break;
}
for(int i = 1; i < countNum; i++){
first = first.next;
lastNode = lastNode.next;
}
// delete curNode from circle.
System.out.print(first.no + " -> ");
first = first.next;
lastNode.next = first;
}
System.out.print("LastNode:" + first.no);
}
//main function
public static void main (String[] args) throws java.lang.Exception
{
CircleSingleLinkedList circle = new CircleSingleLinkedList();
circle.createCircle(5);
circle.visitCircle();
circle.outCircle(1,2,5);
}
}