使用java的循环单向链表解决约瑟夫问题
什么是约瑟夫问题
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?
约瑟夫的故事比较残忍,我们把约瑟夫问题改为一个小游戏,游戏规则如下:
假设编号为1,2,3...n个人手拉手围坐在一圈,约定编号为k(1<= k <= n)的人开始报数,数到m的人出圈,他的下一位又从1开始报数,数到m的人又出圈,依次类推,直到剩余一个人即为胜出者,由此产生一个出圈编号的序列,
使用循环链表模拟n个人围坐一圈
首先我们定义一个循环链表,由此来模拟n个人围坐在一圈。下面先看下单链表的实现代码
/**
* 单向循环链表
*/
class CycleSingleLinkedList{
PersonalNode first = null;
/**
* 向循环链表中添加num个节点
* @param num
*/
public void add(int num){
if(num < 1){
System.out.printf("参数不合法");
return;
}
PersonalNode curr = null;
for (int i = 1; i <=num; i++) {
PersonalNode personalNode = new PersonalNode(i);
if(i == 1){
//添加第一个节点
first = personalNode;
curr = first;
curr.setNext(first);
}else {
curr.setNext(personalNode);
personalNode.setNext(first);
curr = personalNode;
}
} } } /**
* 人物节点
*/
class PersonalNode {
private int no;
private PersonalNode next; public PersonalNode(int no){
this.no = no;
} public int getNo() {
return no;
} public void setNo(int no) {
this.no = no;
} public PersonalNode getNext() {
return next;
} public void setNext(PersonalNode next) {
this.next = next;
}
}
下面我们用图例的方式讲解一下添加n个节点的循环链表的流程,当创建第一个节点时,我们让first和current指向第一个节点,并将current的next指向first节点,以此来形成一个循环。当添加第二个节点时,我们将current的next指针指向第二个节点,第二个节点的next指向first,然后将current后移,即current指向第二个节点,以此类推。

现在我们问题的第一步即n个人围坐在一起解决了,下面来实现第二步从第k个人开始数数。第二步比较简单,即让first指针后移k-1次,由此让first指针指向第一个数数的人。但由于first指向的节点需要出圈,这里我们再定义一个helper指针,来指向first指针的前一个节点,即让helper指针首先指向first,依此循环直到helper的next指针等于first(因为是循环链表)。并保持helper指针始终在first指针的前一个节点(只有一个节点时与first指针指向同一个节点)。假设k=2即从第二个人开始数,m=3即数到3的人出圈,如下图所示

找到node4的人出圈,这时让helper的next等于first的next,然后让first等于helper的next,如下图所示

继续从node1开始数,数到3,即node3出圈,此时指针指向情况如下图

node3出圈后,下一个要出圈的为node1,依此循环,直到helper与first指针指向相同节点,即node2为最后一个要出圈的人。代码如下
/**
* 约瑟夫问题
* @param n n个人围成圈
* @param k 第k个人开始报数
* @param m 数到m的人出圈
*/
public void joseph(int n,int k,int m){
//添加n个人
add(n);
//helper指针指向first的前一个节点
PersonalNode helper = first;
while (helper.getNext() != first){
helper = helper.getNext();
}
//找到第k个人
for (int i = 0; i < (k-1); i++) {
first = first.getNext();
helper = helper.getNext();
}
//数到m的人出圈
while (true){
if(helper == first){
break;
}
for (int i = 0; i < (m-1); i++) {
first = first.getNext();
helper = helper.getNext();
}
System.out.printf("编号为%d的人出圈\n",first.getNo());
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后出圈的人是:"+first.getNo()); }
测试代码
public static void main(String []args){
CycleSingleLinkedList linkedList = new CycleSingleLinkedList();
linkedList.joseph(4,2,3);
}
测试结果:

总结
以上就是实现约瑟夫问题的循环链表解决思路,当然肯定还有很多别的解决思路,欢迎留言探讨,谢谢。
使用java的循环单向链表解决约瑟夫问题的更多相关文章
- c++(循环单向链表)
前面的博客中,我们曾经有一篇专门讲到单向链表的内容.那么今天讨论的链表和上次讨论的链表有什么不同呢?重点就在这个"循环"上面.有了循环,意味着我们可以从任何一个链表节点开始工作,可 ...
- PHP算法学习(8) 环形链表 解决约瑟夫问题
2019年2月25日17:29:17 Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓.于是决定了自杀方式,41个人排成一个圆圈 ...
- php实现单,双向链表,环形链表解决约瑟夫问题
传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季 http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求 ...
- 单向环形链表解决约瑟夫环(Josephus)问题
一.约瑟夫环问题 Josephu 问题为:设编号为1,2,- n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那 ...
- C语言单向循环链表解决约瑟夫问题
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,4 ...
- java判断一个单向链表是否有环路
今天刷LeetCode刷到一道这样的题,详情参见(https://leetcode-cn.com/problems/linked-list-cycle/) ADT: class ListNode { ...
- java 模拟一个单向链表
class Node { //当前节点 private String data; //下个节点 private Node next; //当前节点 public void setData(String ...
- Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)
1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m ...
- 循环列表的Java实现,解决约瑟夫环问题
import java.util.Scanner; /** * 循环列表的Java实现,解决约瑟夫环问题 * * @author LIU * */ public class LinkedList { ...
随机推荐
- 从0到1体验Jenkins+Docker+Git+Registry实现CI自动化发布
一.前言 Jenkins是一款开源 CI&CD 软件,用于自动化各种任务,包括构建.测试和部署软件.Jenkins 支持各种运行方式,可通过系统包.Docker 或者通过一个独立的 Java ...
- 最简单流处理引擎——Kafka Streaming简介
Kafka在0.10.0.0版本以前的定位是分布式,分区化的,带备份机制的日志提交服务.而kafka在这之前也没有提供数据处理的顾服务.大家的流处理计算主要是还是依赖于Storm,Spark Stre ...
- 良许 | 网络检测神器 ss 命令,你可能根本就不会用!
今天我们来介绍一下 Linux ss 命令. ss 是 Socket Statistics 的缩写,用来统计 socket 连接的相关信息,它跟 netstat 差不多,但有着比 netstat 更强 ...
- 第二十四届全国青少年信息学奥林匹克联赛初赛 普及组C++语言试题
第二十四届全国青少年信息学奥林匹克联赛初赛 普及组C++语言试题 1.原题呈现 2.试题答案 3.题目解析 因博客园无法打出公式等,所以给你们几个小编推荐的链接去看看,在这里小编深感抱歉! https ...
- C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性
系列目录 [已更新最新开发文章,点击查看详细] 本篇主要介绍如何获取单文件/模型下单个构建的属性信息. 请求地址:GET https://api.bimface.com/data/v2/fil ...
- CodeForces 628 D Magic Numbers 数位DP
Magic Numbers 题意: 题意比较难读:首先对于一个串来说, 如果他是d-串, 那么他的第偶数个字符都是是d,第奇数个字符都不是d. 然后求[L, R]里面的多少个数是d-串,且是m的倍数. ...
- codeforces 486 D. Valid Sets(树形dp)
题目链接:http://codeforces.com/contest/486/problem/D 题意:给出n个点,还有n-1条边的信息,问这些点共能构成几棵满足要求的树,构成树的条件是. 1)首先这 ...
- Python——最美丽的编程语言
之前总听别人说Python有多厉害,有多好,我是不以为然的.但是当我开始接触Python的时候,我就知道它被誉为最美编程语言不是没有道理的.简短的代码,清晰明了的逻辑,方便快捷的编程工具让它注定会大放 ...
- 【Offer】[6] 【从尾到头打印链表】
题目描述 思路分析 Java代码 代码链接 题目描述 从尾到头打印链表,将其添加到ArrayList当中输出 思路分析 递归的思路 利用栈 Java代码 public class Offer006 { ...
- Ansible实现批量管理服务器
Ansible介绍: a. ansible是一个基于Python开发的自动化运维工具b. ansible是一个基于ssh协议实现远程管理的工具c. ansible软件可以实现多种批量管理操作(批量系统 ...