摘要:在这个问题中,N个人围成一圈,从第一个人开始报数,每数到第M个人,该人就必须离开(或被杀掉),然后由下一个人重新开始报数,直到最后只剩下一个人。这个问题通常被称为约瑟夫环或“丢手绢问题”,并以弗拉维奥·约瑟夫斯(Flavius Josephus)命名,他是一位1世纪的犹太历史学家。
在Java中又该如何解决这个问题呢?创建节点--->创建环形链表--->计算出圈顺序。
1.先创建一个Boy类(链表节点)
class Boy{
private int num;
private Boy next;//下一个节点,默认为null
public Boy(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
}
2.创建一个环形链表
//创建环形链表
class CircleSingleLinkedList{
//创建first节点
private Boy first = null;//也可以是 =new Boy(-1),只要是让第一个节点不存在就可以
//添加节点
public void addBoy(int nums){//nums代表圈内小孩的个数
if (nums < 1){
System.out.println("输入的小孩不对");
return;
}
//定义临时变量
Boy curBoy = null;//辅助指针
for (int i = 1; i <= nums; i++) {
Boy boy = new Boy(i);//每循环一次根据序号创建一个Boy节点
if (i == 1){
first = boy;
first.setNext(first);
curBoy = first;//curBoy指向第一个小孩
}else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;//curBoy指向这个boy
}
}
}
3.计算出圈顺序
思路:
//根据用户的输入,计算出小孩出圈顺序
/*
* startNo:表示从第几个小孩开始数数
* countNum 表示数几下
* nums 表示最初有多少小孩在圈中
* */
public void countBoy(int startNo, int countNum,int nums){
//判断链表是否为空
if (first == null || startNo > nums || startNo < 1){
System.out.println("不符合");
return;
}
//创建一个辅助指针helper,事先指向环形链表的最后一个节点
Boy helper = first;
while (true){
if (helper.getNext() == first){//当helper的next指向了frist就说明到最后了
break;
}
helper = helper.getNext();
}
//报数前,让first和helper移动startNo -1次
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//报数时,让first和helper同时移动countNum - 1次
while (true){
if (helper == first){//说明圈中只有一个节点
break;
}
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//这时候first指向的节点就是要出圈的节点
System.out.println("出圈的节点是" + first.getNum());
//这时侯first指向的就是要删除的节点
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后留下了的节点" + first.getNum());
}
补充 : //这时侯first指向的就是要删除的节点
first = first.getNext();
helper.setNext(first);这一步的图解:
4.测试
/*
* 约瑟夫问题--环形链表
* */
public class Josepfu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(5);
circleSingleLinkedList.countBoy(1,2,5);//第1个开始数,数2下,最初有5个小孩在链表中
}
}