什么是约瑟夫问题
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
创建节点类
class Boy{
//小孩编号
private int no;
private Boy nextBoy;
public Boy(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getNextBoy() {
return nextBoy;
}
public void setNextBoy(Boy nextBoy) {
this.nextBoy = nextBoy;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
}
创建循环链表
/**
* 指向第一个节点
*/
Boy first = null;
/**
* 创建循环链表
* @Param nums :玩家个数
*/
public void createBoys(int nums){
//辅助节点
Boy curBoy = null;
//合法性校验,必须>=1
if (nums <1){
System.out.println("玩家不足,不能开始游戏");
//退出
return;
}
for (int i = 1; i <= nums; i++) {
//循环创建玩家
Boy boy = new Boy(i);
//如果是第一个,则指向自身
if (i == 1){
first = boy;
boy.setNextBoy(first);
curBoy = boy;
}
//不是第一个节点
else{
//设置当前节点的下一个节点为新节点
curBoy.setNextBoy(boy);
//当前节点指向新节点
curBoy = boy;
//新节点指向第一个节点
boy.setNextBoy(first);
}
}
}
遍历循环链表
/**
* 遍历循环链表
*/
public void showBoys(){
//1判断链表是否为空
if (null == first){
System.out.println("当前链表为空");
return;
}
//设置辅助节点
Boy cur = first;
boolean notLast = false;
while (!notLast){
System.out.println("小孩的编号是:"+cur.getNo());
if (cur.getNextBoy() == first){
//代表是最后一个小孩了
notLast = true;
}
//当前指针后移
cur = cur.getNextBoy();
}
}
按照约瑟夫法则出圈
/**
* 按照约瑟夫法则出圈,报到countNum的小孩出圈
* @param nums 小孩的个数
* @param startNo 开始报数的小孩
* @param countNum 报数多少次
*/
public void selectBoy(int nums,int startNo,int countNum){
//合法性校验
if (first == null ){
System.out.println("圈中没小孩");
return;
}
if (nums < 1 || startNo > nums){
System.out.println("输入参数有误,请重新输入");
//nums = 输入;
//startNo = 输入;
return;
}
//1创建一个helper指针指向first的前一个
Boy helper = first;
while (true){
if (helper.getNextBoy() == first){
//helper为最后一个
break;
}
helper = helper.getNextBoy();
}
//2报数前让first移动到开始位置,helper移动到first前一个位置,移动 startNo-1 次
for (int i = 0; i < startNo-1; i++) {
first = first.getNextBoy();
helper = helper.getNextBoy();
}
//3开始报数
while (true){
//什么时候退出循环?
if (first == helper){
// 圈中只剩一个小孩
break;
}
//循环countNum-1次(因为自己就占了一次),寻找出圈小伙子
for (int i = 0; i < countNum-1; i++) {
first = first.getNextBoy();
helper = helper.getNextBoy();
}
//输出出圈的小孩,first就是要出圈的小孩
System.out.printf("出圈的是 %d 号小孩\n",first.getNo());
//出圈操作
// first 后移
first = first.getNextBoy();
//helper 指向first
helper.setNextBoy(first);
}
//出圈完毕,打印最后一个小孩
System.out.println("圈中最后一个小孩是:"+first.getNo());
}
结果