数据结构与算法: 约瑟夫(丢手绢)问题(单向链表,双向链表解决)

Tips: 采用java语言, 关注博主,底部附有完整代码

采用到的知识点:

  • 单向环形链表
  • 双向环形链表
  • 单向 / 双向 环形链表出圈

流程效果图:

单向环形链表 双向环形链表

什么是约瑟夫问题

约瑟夫问题好像小时候玩的丢手绢一样

先来说一下规则, 默认从第一个小朋友开始数,在第n个小朋友过后开始寻手绢, 第n个小朋友每k个人就丢下手绢,然后这个小朋友出圈

直到圈中只剩一人才结束

假设5个小朋友围坐一圈来丢手绢

例如这样:

在第2个小朋友开始丢手绢

那么就是元素三出圈

接着每2个元素依次出圈

tips: 这里单向环形链表和双向环形链表思路有所不同, 所以结果也有所不同!

  • 单向环形链表 先创建好5个元素 然后从第n个孩子开始,每k次出圈 , (第一次从第n个孩子数也会出圈)
  • 双向环形链表 直接调用一个方法,并且传入需要“丢手绢”的元素,在开始出圈 (第一次从第n个孩子数也不会出圈)

单向环形链表

自定义链表 AnnularLinkedList.java:

public class AnnularLinkedList {//头节点private HeroNode3 head;/*** get头节点* @return 头节点*/public HeroNode3 getHead() {return head;}/*** 创建元素* @param sum 需要创建的个数*/public void createHeroNode(int sum) {if (sum < 1) {System.out.println("请正确输入创建个数");return;}HeroNode3 temp = null;for (int i = 1; i <= sum; i++) {HeroNode3 node3 = new HeroNode3(i, "张三" + i);if (i == 1) {//记录第一个位置head = node3;//辅助变量,记录第一个位置temp = node3;//第一个元素指向自己,构建成环形head.next = head;}//指向新的元素temp.next = node3;//新的元素指向第一个节点node3.next = head;//temp后移temp = temp.next;}}/*** @param start  从元素几开始数* @param number 每数几下出圈*/public void count(int start, int number) {//获取链表长度int sum = size();System.out.println("sum为:" + start + "\t" + number + "\t" + sum);//start < 1  不能从 < 1 开始的数 数//sum < start  链表总数不能 < 开始的位置if (start < 1 || sum < start) {System.out.println("请正确输入");return;}HeroNode3 help = head;//将 help 移动到 head 后面while (help.next != head) {help = help.next;}//从第start位置开始循环for (int i = 0; i < start - 1; i++) {head = head.next;help = help.next;}//如果heap != head 那么就继续循环//当help == head 时,则退出循环while (help != head) {//每number下出圈for (int i = 0; i < number - 1; i++) {head = head.next;help = help.next;}//此时head则为要出圈的元素System.out.println("要出圈的勇士id为:" + head.id);//出圈操作head = head.next;help.next = head;}//最终help = head  那么help/head就是最后一个在圈中的元素System.out.println("留在圈中的勇士id为:" + help.id);}/*** 计算链表长度*/public int size() {int length = 1;HeroNode3 temp = head;while (temp.next != head) {length++;temp = temp.next;}return length;}/*** 输出链表所有数据*/public void show() {if (head == null) {System.out.println("链表为null,不能打印");}HeroNode3 temp = head;while (temp.next != null) {System.out.println("show:" + temp);//当最后一个元素 = 第一个元素时,表示链表当前在最后一个元素,停止循环if (temp.next == head) {break;}//temp后移temp = temp.next;}}
}

HeroNode3.java:

public class HeroNode3 {int id;String name;HeroNode3 next;public HeroNode3(int id, String name) {this.id = id;this.name = name;}@Overridepublic String toString() {return "HeroNode3{" +"id=" + id +", name='" + name + '\'' +'}';}
}

调用:

AnnularLinkedList linkedList = new AnnularLinkedList();linkedList.createHeroNode(5);System.out.println("测试的值为:"+linkedList.getHead().next.next.next.next.next.next);linkedList.show();linkedList.count(2, 2);

来看看运行结果:

如果对单向链表或者约瑟夫问题陌生的,项目中还有我画的2张详细流程图 那就下载看看吧

双向环形链表

AnnularDoubleLinkedList.java

/*** @author: android 超级兵* @create: 2022-05-05 11:53* TODO 约瑟夫问题 双向链表**/
public class AnnularDoubleLinkedList {public AnnularHeroNode headNode = new AnnularHeroNode();/*** TODO 约瑟夫问题 双向链表** @param n    从第几个开始 (0 - list.size())* @param k    每次走几个 (k < list.size())* @param list 元素*/public void josephusProblem(int n, int k, List<AnnularHeroNode> list) {if (list.size() < n) {System.out.printf("当前元素一共%d个,无法从第%d个元素开始", list.size(), n);return;}headNode = list.get(0);// TODO 先将每个元素链接起来for (int i = 0; i < list.size(); i++) {AnnularHeroNode node = list.get(i);// 下一个元素AnnularHeroNode nextNode;if (i != list.size() - 1) {nextNode = list.get(i + 1);} else {// 最后一个节点node.setLastNode(true);nextNode = list.get(0);}node.next = nextNode;nextNode.pre = node;}System.out.println("测试是否成功:");System.out.println(headNode.next.next.next.next);System.out.println(headNode.pre.pre.pre.pre);System.out.printf("最后一个节点为:%s\n", headNode.pre);System.out.printf("第一个节点为:%s\n", headNode);show();// 从第几个元素开始AnnularHeroNode tempNode = list.get(n);System.out.printf("从%s开始\n", tempNode);System.out.println();AnnularHeroNode currentNode = null;// 当前节点上一个节点AnnularHeroNode currentPreNode = null;while (true) {// 每次过n个人for (int i = 0; i < k; i++) {currentNode = tempNode.next;tempNode = tempNode.next;}System.out.printf("currentNode:%s\n", currentNode);// 移除当前选中的currentNode.pre.next = currentNode.next;currentNode.next.pre = currentNode.pre;// 当前位置的最后一个位置currentPreNode = currentNode.pre;// 如果当前位置后一个位置 = 当前位置 说明只有一个,则退出循环if (currentPreNode == currentNode) {break;}}System.out.printf("最终留在圈中的是  %s\n", currentNode);}private void show() {System.out.println("\n遍历: ======= start =======");AnnularHeroNode tempHeadNode = headNode;while (true) {System.out.println(tempHeadNode);if (tempHeadNode.isLastNode()) {break;}tempHeadNode = tempHeadNode.next;}System.out.println("遍历:  ======= end =======\n");}
}

AnnularHeroNode.java

/*** @author: android 超级兵* @create: 2022-05-05 11:54* TODO**/
public class AnnularHeroNode {private final int id;private final String name;private final String title;// 是否是最后一个节点private boolean isLastNode;// 下一个节点public AnnularHeroNode next;// 上一个节点public AnnularHeroNode pre;public AnnularHeroNode() {id = 0;name = "";title = "";}public int getId() {return id;}public AnnularHeroNode(int id, String name, String title) {this.id = id;this.name = name;this.title = title;}public boolean isLastNode() {return isLastNode;}public void setLastNode(boolean lastNode) {isLastNode = lastNode;}@Overridepublic String toString() {return "AnnularHeroNode{" +"id=" + id +", name='" + name + '\'' +", title='" + title + '\'' +", isLastNode='" + isLastNode + '\'' +'}';}
}

使用:

package a20220505环形双向列表;import java.util.ArrayList;/*** @author: android 超级兵* @create: 2022-05-05 12:07* TODO 约瑟夫问题 双向链表解决**/
public class Client {public static void main(String[] args) {AnnularDoubleLinkedList annularDoubleLinkedList = new AnnularDoubleLinkedList();AnnularHeroNode node0 = new AnnularHeroNode(0, "史进", "九纹龙");AnnularHeroNode node1 = new AnnularHeroNode(1, "鲁智深", "花和尚");AnnularHeroNode node2 = new AnnularHeroNode(2, "林冲", "豹子头");AnnularHeroNode node3 = new AnnularHeroNode(3, "宋万", "云里金刚");AnnularHeroNode node4 = new AnnularHeroNode(4, "吴用", "智多星");ArrayList<AnnularHeroNode> nodeArrayList = new ArrayList<>();nodeArrayList.add(node0);nodeArrayList.add(node1);nodeArrayList.add(node2);nodeArrayList.add(node3);nodeArrayList.add(node4);// 23401annularDoubleLinkedList.josephusProblem(1, 2, nodeArrayList);}
}

完整代码

原创不易,您的点赞与关注就是对我最大的支持!

数据结构与算法: 约瑟夫问题(丢手绢)相关推荐

  1. Java中使用链表解决约瑟夫问题(丢手绢问题)

    文章目录 文章目录 前言 一.思路分析 二.代码实现 1.Chird类建立 2.链表创建 3.功能实现 总结 其他解决方式: Java中使用list解决约瑟夫问题https://blog.csdn.n ...

  2. Java中使用list解决约瑟夫问题(丢手绢问题)

    文章目录 文章目录 前言 一.思路分析 二.代码实现 总结 其他解决方式: Java中使用环形链表解决约瑟夫问题https://blog.csdn.net/qq_35813811/article/de ...

  3. 约瑟夫环 -- 丢手绢问题

    问题描述 约瑟夫环问题,也称为"丢手绢问题". 编号为 1-N 的 N 个士兵围坐在一起形成一个圆圈,从编号为 1 的士兵开始依次报数(1,2,3-这样依次报),数到 m 的 士兵 ...

  4. Algorithm One Day One -- 约瑟夫环(丢手绢问题)

    算法是编程的灵魂,是编程思想的精髓----Algorithm One Day One /******************************************************** ...

  5. C语言||约瑟夫问题(丢手绢问题)

    20518 用时:1h 编程数组或指针实现约瑟夫环问题. 题目为:编号为1,2- n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺 ...

  6. 数据结构与算法 — 约瑟夫问题(Josephu)

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

  7. 约瑟夫问题(丢手绢问题)

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

  8. 数据结构与算法--我们来玩丢手绢(约瑟夫环问题)

    我们来玩丢手绢 昨天我们打扑克,今天我们丢手绢 丢手绢我们都知道这个游戏,他的由来由约瑟夫 (Josephus)提出来的 据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,3 ...

  9. Java数据结构单向循环链表实现约瑟夫问题(丢手绢)

    环形链表 实例:使用环形链表解决约瑟夫问题(丢手绢) 构建一个单向环形链表思路 ​ 1)先创建第一个节点,让first指向该节点,并形成环形 ​ 2)加入环形链表 遍历环形链表 ​ 1)先让一个辅助指 ...

最新文章

  1. java基本类型转换,随记
  2. 群晖共享文件夹局域网通过SMB本地访问
  3. HTTP协议解析之Cookie
  4. 胶囊网络为何如此热门?与卷积神经网络相比谁能更胜一筹?
  5. R语言使用yardstick包的lift_curve函数评估多分类(Multiclass)模型的性能、并使用autoplot函数可视化模型在每个交叉验证(或者重采样)的每一折fold在每个分类上的提升
  6. 字符串分隔 -连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组; •长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。...
  7. java如何对list进行排序_java中如何对list进行排序
  8. matlab 数值解 期权顶级啊,潮盈期权院高胜率交易技巧系列之二----期权交易策略及基于MATLAB统计套利介绍...
  9. SAP License:家装ERP
  10. TurboMail邮件服务器腾云驾务云化邮件办公
  11. EGit/User Guide
  12. Pytorch模型参数的访问、初始化和共享
  13. java程序员和java架构师有什么区别呢?
  14. mysql8.0怎么设置中文版_mysql 8.0.21免安装版配置方法图文教程
  15. 92套AE抖音快闪模板(精品)
  16. 2011美剧季终/剧终时间表。
  17. Temporal Action Detection with Multi-level Supervision UFA论文阅读笔记
  18. Oracle 绑定变量详解
  19. 条件与循环Phython
  20. 数据结构考研:大O表示法最浅显易懂且详细深入的解释及与小o表示法的区别(十分钟必懂)

热门文章

  1. 联想微型计算机开机密码忘记了,lenovo台式电脑忘了开机密码简单解决的方法,小孩子就能搞定的...
  2. Fairware勒索软件频繁攻击Linux服务器 大家赶紧做好备份
  3. android原生widget 电量控制(PowerSave)设计浅析
  4. python如何打出英文括号_用python的re(正则表达式)模块匹配英文环境下的括号
  5. 如何远程办公 远程办公操作指南 7款好用的远程办公软件
  6. CSDN 软件开发新手赛正式启动,召集热爱编程的你
  7. 从Office 2010的华丽转型看微软的战略野心
  8. K8S太火了!花10分钟玩转它不香么,面试必备知识点
  9. matlab对于椭圆检测的算法,基于弧段组合的椭圆检测算法研究
  10. Java 抽奖系统扩展