看小朋友做游戏顿时解决了约瑟夫问题
Posted 冷环渊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了看小朋友做游戏顿时解决了约瑟夫问题相关的知识,希望对你有一定的参考价值。
前言
★ 这里是小冷的博客
✓ 优质技术好文见专栏
个人公众号,分享一些技术上的文章,以及遇到的坑
当前系列:数据结构系列
源代码 git 仓库 ‘
数据结构代码地址 代码Git 仓库地址
环形链表
认识单向环形链表
这里我们以单向环形链表为例子
就是我们最后一个节点的next域指向头结点,形成闭环
引用场景以及问题
Josephu(约瑟夫、约瑟夫环) 问题
Josephu 问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数 到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由
此产生一个出队编号的序列。
思路提示:
提示:用一个不带头结点的循环链表来处理 Josephu 问题:先构成一个有 n 个结点的单循环链表,然后由 k 结 点起从 1 开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从 1 开始计数,直 到最后一个结点从链表中删除算法结束。
Josephu 问题解题思路
认识约瑟夫问题,以及我们想要实现的场景,
- 编写实现 单向环形链表
- 约瑟夫问题的要求 根据区间报数 报数的小孩出列
- coding 出我们需要的需求
实现单向循环链表
思路
大体上和我们的单向链表有雷同的地方,区别在于:
- 我们需要在创建链表的时候将尾结点的最后一个指向头结点,这也就意味着我们需要有至少两个指针来记录头尾节点。
- 遍历的方式也要有些许的变化,结束循环的条件从
head.next = null
改变成CurBoy.next(指向尾部节点的指针) = first;
最后为头节点的时候遍历为第二个
我们简单的先创建一个实现链表需要的节点对象
约瑟夫问题环形链表的节点
//环形链表 约瑟夫问题 节点
class Boy
private int No;
private Boy Next;
public Boy(int no)
this.No = no;
public int getNo()
return No;
public void setNo(int no)
No = no;
public Boy getNext()
return Next;
public void setNext(Boy next)
Next = next;
创建环形链表对象实现生成链表和遍历链表,以及解决约瑟夫问题的方(具体的实现思路见代码注释)
// 环形单向链表
class CircleSingleLinkeList
Boy first = null;
/**
* @author 冷环渊 Doomwatcher
* @context: 一个环形链表 参数是这个链表有多少节点
* @date: 2021/12/21 15:47
* @param nums
* @return: void
*/
public void CreateListNode(int nums)
if (nums < 1)
System.out.println("无法开始游戏,因为链表小于最小的游戏节点数量");
return;
// 创建一个 辅助之间用于遍历和指向节点
Boy curBoy = null;
for (int i = 1; i <= nums; i++)
Boy boy = new Boy(i);
//如果只有一个节点的话 也可以生成环形链表
if (i == 1)
first = boy;
first.setNext(first);
curBoy = first;//将辅助指针指向链表的第一个节点 形成闭环
else
// 如果不是一个的话就生成多个节点
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;
public void showListBoy()
if (first == null)
System.out.println("链表为空,不能遍历");
return;
// frist 节点不能移动 我们创建一个指针
Boy curboy = first;
while (true)
System.out.printf("小孩的编号是: %d \\n", curboy.getNo());
// 说明已经遍历完毕
if (curboy.getNext() == first)
break;
//后移 curboy
curboy = curboy.getNext();
/**
* @author 冷环渊 Doomwatcher
* @context: 这里我们以小孩做游戏来解决约瑟夫问题,
* @date: 2021/12/22 21:16
* @param nums 一共有多少个小孩
* @param start 从那个小孩开始报数
* @param index 每隔几个小孩报数一次
* @return: void
*/
public void JosephuFunc(int nums, int start, int index)
if (first == null || start < 1 || start > nums)
System.out.println("参数不对,请重新输入参数");
return;
Boy helper = first;
//将 helper遍历到最后一个节点
while (true)
if (helper.getNext() == first)
break;
helper = helper.getNext();
// 小孩子 报数之前,要遍历指针到从start开始的小孩的节点
for (int i = 0; i < start - 1; i++)
first = first.getNext();
helper = helper.getNext();
//当小孩报数的时候 让 first和helper 同时移动m-1次 然后出圈
//这里循环操作 知道圈中的一个节点
while (true)
//说明列表只有一个节点
if (helper == first)
break;
//循环之后将 指针后移
for (int i = 0; i < index - 1; i++)
first = first.getNext();
helper = helper.getNext();
// 这个时候 first选中的节点就是要出圈的小孩
System.out.printf("小孩 %d 出圈\\n", first.getNo());
//出圈操作
first = first.getNext();
helper.setNext(first);
System.out.printf("最后剩下的小孩 %d \\n", first.getNo());
实现结果
以上是关于看小朋友做游戏顿时解决了约瑟夫问题的主要内容,如果未能解决你的问题,请参考以下文章