自己选择的程序员的这条路,跪也要跪到终点。

文章目录

  • 什么是约瑟夫问题
  • 问题解决
    • 实现思路
      • 我们需要定义一个多大的数组?
      • 起始值怎么选取
      • 我们怎么计算叫到哪个小朋友了
      • 小朋友出队列了,我们怎么模拟剩下的小朋友
    • 具体代码实现
  • 总结
  • 另一种实现方式的代码

什么是约瑟夫问题

约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的 算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”)。

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

上面这种说法未免太过暴力,我们可以想成有几个小朋友围成一圈,老师指定一小朋友开始报数,没报数3次,当前的小朋友就去自由活动,一直到所有的小朋友都去玩游戏了。那么小朋友去玩游戏的顺序是怎么样的。

问题解决

程序 = 数据结构 + 算法。
拿到这个问题,我们首先要思考,要用什么样的数据结构去承载这个题目。目前主流的实现方式,总结下来有两种。数组和单向循环链表,我们本篇文章先用数组来实现。

实现思路

要想用数组来解决这个问题,我们要先解决一下几个问题。

我们需要定义一个多大的数组?

数组这种数据结构是长度固定的,而且是内存连续分布的,你如果想用数据解决这个问题的话,数组的长度是首先需要考虑,上述题目是将小朋友们定义成了一个圈,是不断出圈的。所以我们的数组长度可以定为小朋友的个数,因为我们只有这么多小朋友,多了也不需要。假设我们一共有六个小朋友,那么我们就需要一个size为6的数组。
那么我们以下图为例,数组的每一个内存空间内存放一个小朋友,编号是从一到六。但是我们数组的下角标是从0开始,因此我们数组存放的数字要比指针的位置大1。

起始值怎么选取

我们那么就要开始数数了,老师需要规定从第几个小朋友开始,这个比较简单,从第几个开始,就是从数组中取第几个减一作为起始值即可(因为小朋友的编号比下角标大1)。

我们怎么计算叫到哪个小朋友了

这个问题是数组实现最关键的一步,有的小伙伴说这还不简单,不就是往后移动n-1次么(n是喊几个数一停)。这是没有问题的,问题的关键在于, 数组不是环形的,如果是第四个小朋友开始叫数的,每三个数一停,你就会发现,你的数组越界了,因此我们需要当数组到了尽头还能从第一个小朋友连上,这就需要我们数学中的取模了,就拿上面的举个例子,第四个开始叫,三个一停。我们的做法应该是 (4+3)%6 ,我们可以看到结果是1,至于为么要这样你可以把数组想象成一个圆环自己画一下。慢慢就理解了,这种思想在算法中很重要,一定要理解。

小朋友出队列了,我们怎么模拟剩下的小朋友

如果有一个小朋友已经出队去玩了,那么剩下的小朋友就是之前的size-1,因为我们每次只出去一个小朋友。我们的做法是没出去一个,就将这个小朋友之后的小朋友都进一个,最后一个空出来置为0。这个操作什么时候结束呢,就是等数组的第一个都为0了,说明我们已经没有小朋友了。就可以循环结束了。

具体代码实现

    /*** 使用数组实现约瑟夫环** @param begin 从第几个小朋友开始* @param number 一次叫几个小朋友* @param count 一个多少个小朋友参与*/public static void jonsephuArray(int begin, int number, int count) {int[] arr = new int[count];for (int i = 0; i < arr.length; i++) {arr[i] = i + 1;}// 这里指的是数组的下脚标int current = begin - 1;int size = arr.length;while (arr[0] != 0) {current = (current + (number - 1)) % size;System.out.println(arr[current] + " 出圈");// 后面的数组向前移动一个, 并把size-1位置为0for (int i = current; i < size; i++) {if (i == size - 1) {arr[i] = 0;break;}arr[i] = arr[i + 1];}size--;}}

代码中需要注意的一点是, 记得size每次要减一,否则我们每次都是将最后一个置为0,会有死循环的发生。

总结

这种方式是我所知道代码量最少的一种实现方式,但是本人是不太建议,我觉得单项循环链表更加贴合这道题的逻辑,但是单向循环链表实现起来代码量要大一些。我先把我用单向循环链表实现的代码贴在下面,有需要的童鞋,我会再写一篇博客进行讲解。

另一种实现方式的代码

/*** 循环链表*/
class CycleLinkedList {private BoyNode firstNode;/*** 向环形队列中添加孩子*/public CycleLinkedList addBoys(int count) {BoyNode currentBoy = null;for (int i = 1; i <= count; i++) {if (i == 1) {firstNode = new BoyNode() {{no = 1;next = firstNode;}};currentBoy = firstNode;continue;}BoyNode node = new BoyNode();node.no = i;currentBoy.next = node;node.next = firstNode;currentBoy = node;}return this;}/*** 打印循环链表*/public void printBoyNodeList() {if (firstNode == null) {System.out.println("啥也没有,你打印个啥???");return;}BoyNode node = firstNode;while (true) {if (node.next == firstNode) {System.out.println(node.no);break;}System.out.println(node.no);node = node.next;}}/*** @param begin  从第几个人开始* @param number 一次喊几个人* @param count  一共多少人参与游戏*/public void start(int begin, int number, int count) {addBoys(count);// 定义followNode节点, 并移动该节点到firstNode节点的后面BoyNode followNode;BoyNode temp = firstNode;while (true) {if (temp.next == firstNode) {followNode = temp;break;}temp = temp.next;}// 将firstNode和followNode移动到开始的位置for (int i = 0; i < begin - 1; i++) {followNode = firstNode;firstNode = firstNode.next;}// 开始叫人while (true) {if (followNode == firstNode) {System.out.println(firstNode.no + "出圈");break;}for (int i = 0; i < number - 1; i++) {followNode = firstNode;firstNode = firstNode.next;}System.out.println(firstNode.no + "出圈");followNode.next = firstNode.next;firstNode = firstNode.next;}}
}/*** 丢手绢的孩子节点*/
class BoyNode {// 孩子的编号int no;// 孩子下个人是BoyNode next;
}

JAVA实现约瑟夫问题相关推荐

  1. 用java解决约瑟夫循环问题_Java采用循环链表结构求解约瑟夫问题

    本文实例讲述了Java采用循环链表结构求解约瑟夫问题的方法.分享给大家供大家参考.具体分析如下: 这是第一次java考试的试题,对于没看过链表的同学来说就不会做,现在回头看看,还真不难. 约瑟夫问题: ...

  2. 用java解决约瑟夫循环问题,Java实现循环列表解决约瑟夫环问题

    约瑟夫环:共有n个人围成一圈,从1开始报数,数到m的人出圈,求最后幸运者序号?? 下面用Java实现循环列表解决这个问题: package com.iteye.ljmdbc7a; import jav ...

  3. java实现约瑟夫环完整算法_Java简单实现约瑟夫环算法示例

    Java简单实现约瑟夫环算法示例 发布时间:2020-10-01 14:19:56 来源:脚本之家 阅读:104 作者:perfect亮 本文实例讲述了Java简单实现约瑟夫环算法.分享给大家供大家参 ...

  4. Java实现约瑟夫环问题

    约瑟夫环问题起源于一个犹太故事.约瑟夫环问题的大意如下: 罗马人攻占了桥塔帕特,41个人藏在一个山洞中躲过了这场浩劫.这41个人中,包括历史学家Josephus(约瑟夫)和他的一个朋友.剩余的39个人 ...

  5. Java数据结构-约瑟夫 作者:哇塞大嘴好帥(哇塞大嘴好帅)

    Java 约瑟夫 作者:哇塞大嘴好帥(哇塞大嘴好帅) 作者:哇塞大嘴好帥(哇塞大嘴好帅) 0.Josephu(约瑟夫) 分析 ​ 设编号为1,2,- n的n个人围坐一圈,约定编号为k(1<=k& ...

  6. java解答约瑟夫问题

    据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,4 ...

  7. 【LeetCode笔记】剑指 Offer 62. 圆圈中最后剩下的数字(Java、约瑟夫环、链表)

    文章目录 题目描述 思路 & 代码 链表模拟法 数学方法 二刷 题目描述 约瑟夫环!题目可太经典了 说实话还是有点难度的= = 思路 & 代码 链表模拟法 第一想法是用 LinkedL ...

  8. 约瑟夫环问题链表实现(Java)

    面试中可能经常会遇到约瑟夫环问题,逻辑上很简单,就是看怎么实现了,一般而言,最简单最直观的就是利用链表,然后构建一个循环结构,正好是环,最后计算出结果. 遍历环形链表会是一个无限循环,如果链表中的数据 ...

  9. 【算法-剑指 Offer】62. 圆圈中最后剩下的数字(环形链表;约瑟夫环;动态规划)

    剑指 Offer 62. 圆圈中最后剩下的数字 - 力扣(LeetCode) 发布:2021年9月12日12:18:52 问题描述及示例 0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每 ...

最新文章

  1. python语法面试题_Python语法面试题
  2. 基于linux的驱动设计,《基于LINUX的虚拟驱动设计》-毕业论文.doc
  3. Specification排序orderby
  4. python怎么读文件里的某一行-Python如何获取文件指定行的内容
  5. 【Ansible 文档】【译文】模式
  6. 哎..前段时间的偷懒..造成今天的被动局面...要检讨深刻教训.
  7. 好想学python机器人_【Python成长之路】从零学GUI -- 制作智能聊天机器人
  8. C#:委托基础与事件
  9. oracle创建public链接,如何在oracle直接使用地址来创建database link
  10. E:Tree Queries(假树链剖分写法)
  11. 企业即时通讯最可见的价值是效率和成本
  12. 文件读写'r'和'rb'区别
  13. 陇东学院计算机学院教授有,陇东学院
  14. Atamai 手术导航软件开发包
  15. Codeforces Round #710 (Div. 3)
  16. 一个女算法程序媛的日常
  17. 【转】Content-type的几种常见类型
  18. matlab 图片保存pdf,matlab中的图片保存技巧.pdf
  19. 杨辉三角python小代码
  20. Neo4j AuraDB免费版——Data Importer

热门文章

  1. 物流路径规划用遗传算法解决实例
  2. CSDN红色字体,蓝色字体,字体大小设置
  3. FBAR滤波器的工作原理及制备方法
  4. 【CF#538div2:C】Trailing Loves (or L'oeufs?)(质因数分解+分析)
  5. 看完阿里最新产500页微服务架构笔记,感觉我格局太小
  6. 讲座预告 | 清华软件论坛:Adan: 用于快速优化深层模型的自适应Nesterov动量算法...
  7. 没有备份怎么办?苹果手机怎么恢复误删短信
  8. 深度学习入门(三)——线性代数和概率统计基础
  9. 4000字小红书视频笔记运营干货,教你快速打造爆款笔记
  10. java计算机毕业设计铝塑门窗的研制和生产管理源码+系统+数据库+lw文档+mybatis+运行部署