07 - 单向环形链表应用场景 —— Josephu问题

1. Josephu 问题

设编号为1,2,… n的n个人围坐一圈,约定编号为 k(1<=k<=n)的人从1开始报数,数到 m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列

2. 解决思路

  • 【简述】用一个不带头结点的循环链表来处理Josephu问题, 先构成一个有n个结点的单循环链表,然后由 k 结点 起从1开始计数,计到 m 时,对应结点从链表中删除,然后再从 被删除结点的下一个结点 又从1开始计数,直到最后一个结点从链表中删除算法结束
  • 变量
    • first,指向 编号为k 的结点
    • helper,指向 环形链表first结点 的前一个结点
  • 出圈
    ∵ 报数从1开始,自己本身也算1个数,1到m之间共有 m-1 个空隙
    ∴ first 要移动 m-1 次,方可到达 [数到m的那个人],helper结点也移动 m-1 次,它的作用是辅助first 让 第m个人 出圈

    • first = first.next;
    • helper.next = first;
    • 原来 first 指向的结点因没有任何引用指向它而被垃圾回收器回收

3. 代码实现

直接将该方法加入06的代码实现中即可

    /**
     * 根据用户的输入, 计算出小孩出圈的顺序
     * @param startNo 从编号为startNo的boy开始数数
     * @param countNum 数几下
     * @param nums 最初有多少boy在圈中
     */
    public void countBoy(int startNo, int countNum, int nums) {
        // 0. 数据校验
        if(first == null || startNo < 1 || startNo > nums || countNum < 1) {
            System.out.println("输入数据有误");
            return;
        }
        /*
         * 1. 将first, helper移动到startNo所确定的位置
         *  1.1 helper 应指向 first 的前一个结点
         *  1.2 first 应指向编号为 startNo 的结点, 需移动 startNo-1 次
         *  1.3 helper 也得跟着动
         */
        Boy helper = first;
        while(helper.next != first)
            helper = helper.next;
        for(int i = 0; i < startNo - 1; i++) {
            first = first.next;
            helper = helper.next;
        }

        /* 如果 startNo = 1, 下面这种方法就不对了
        for(int i = 0; i < startNo - 2; i++)
            helper = helper.next;
        // 移动 startNo - 2 + 1 次
        first = helper.next;
        */

        // 2. 开始数数, 让结点逐个出圈
        while(helper != first) { // 说明圈里只有1个结点了
            // 2.1 让first, helper 同时移动 countNum-1 次
            for(int i = 0; i<countNum-1; i++) {
                first = first.next;
                helper = helper.next;
            }
            // 此时, first指向的结点即为 要出圈的结点
            System.out.println("出圈! " + first);
            first = first.next;
            helper.next = first;
            // 出圈结点 此时因没有被任何引用所引用, 而被垃圾回收
        }
        System.out.println("last Node: " + first);
    }
    

原文地址:https://www.cnblogs.com/liujiaqi1101/p/12215389.html

时间: 2024-08-01 01:23:04

07 - 单向环形链表应用场景 —— Josephu问题的相关文章

Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)

1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列. 提示: 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法

单向环形链表

单向环形链表(Josepfu) 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)按顺时针方向围坐在一张圆桌周围,每个人持有一个密码(正整数).一开始任选一个整数作为报数上限值m,从第一个人开始顺时针自1报数,报到m时停止报数,报m的那个人出列,他的密码作为新的m值,从他在顺时针方向上的下一个人又开始重新从1报数,报到m的那个人出列又出列:依此规律重复下去,直到圆桌周围的人全部出列 /* 约瑟夫问题 */ public class Josepfu { pu

实现约瑟夫环形链表

题目 41个人排成一个圆圈,由第1个人 开始报数,每报数到第3人,该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.约瑟夫与朋友在第16与第31个位置,于是活了下来.请用单向环形链表描述该结构并呈现整个自杀过程. 设计 首先要设计一个节点模型 class Node { int value; Node next; Node(int value) { this.value = value; } } 遍历并用 last 节点做成一个单向线性的链表,之后将自身的初始节点指向last.ne

php实现单,双向链表,环形链表解决约瑟夫问题

传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季  http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求不高 但是,如果你开发系统软件,比如(搜索/识别软件[图像,语言识别]/操作系统...)对数学高 建模.大量数学模型. 老师啊啊.我是学C++的.麻烦,谈哈对QT和MFC的看法嘛.前景什么的, 记住 : 打好基础,大有可为! 初中毕业能去传智学习吗? 学习It, 不管是java ,php ,c#,对

双向链表和环形链表(约瑟夫问题)

双向链表 package linkedlist; public class DooubleLinkedListDemo { public static void main(String[] args) { HeroNode2 hero1 = new HeroNode2(1,"宋江","及时雨"); HeroNode2 hero2 = new HeroNode2(2,"卢俊义","玉麒麟"); HeroNode2 hero3 =

C# 数据结构 - 单链表 双链表 环形链表

链表特点(单链表 双链表) 优点:插入和删除非常快.因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作. 缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了.(顺序表可以弥补这缺点,但插入和删除就非常耗性能) 单链表 单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针).最后一个节点的Next为null来标识链表的尾. 如下图 代码实现 1 /* ----

java 环形链表实现约瑟夫(Joseph)问题

约瑟夫问题又名丢手绢问题.相传著名犹太历史学家 Josephus 利用其规则躲过了一场自杀游戏,而后投降了罗马. 问题: 已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.* 从编号为k的人开始报数,数到m的那个人出列:* 他的下一个人又从1开始报数,数到m的那个人又出列:* 依此规律重复下去,直到圆桌周围的人全部出列. 用节点来模拟游戏中的人,用链表来表示游戏中的人按一定的顺序排列.每一个节点给一个编号,从编号为k的节点开始计数,计到m的节点从链表中退出.之后m的下一个节点从新

环形链表与约瑟夫环问题

思路: 代码: public class Josepfu { public static void main(String[] args) { // 测试一把看看构建环形链表,和遍历是否ok CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy(125);// 加入5个小孩节点 circleSingleLinkedList.showBo

c语言:写一个函数建立一个有3名学生数据的单向动态链表

写一个函数建立一个有3名学生数据的单向动态链表. 解:程序: #include<stdio.h> #include<stdlib.h> #define LEN sizeof(struct Student) struct Student { long num; float score; struct Student *next; }; int n; struct Student *creat(void)//定义函数返回一个指向链表头的指针 { struct Student *head