• 【数据结构】环形链表


    一、约瑟夫问题介绍    

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

    1.1 约瑟夫问题示意图

      

    1.2 使用不带头节点的环形单链表解决思路

      用一个不带头结点的循环链表来处理 Josephu 问题:先构成一个有 n 个结点的单循环链表,然后由 k 结点起从 1 开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从 1 开始计数,直到最后一个结点从链表中删除,算法结束。

    1.2.1 创建环形链表思路

      

    1.2.2 小孩出圈思路分析

      

    二、编写Java代码解决问题

    2.1 编写Boy类

     1 /**
     2  * 创建一个Boy类,表示一个节点
     3  */
     4 public class Boy {
     5 
     6     private int no; // 编号
     7     private Boy next; // 指向下一个节点
     8 
     9     public Boy(int no) {
    10         this.no = no;
    11     }
    12 
    13     public int getNo() {
    14         return no;
    15     }
    16 
    17     public void setNo(int no) {
    18         this.no = no;
    19     }
    20 
    21     public Boy getNext() {
    22         return next;
    23     }
    24 
    25     public void setNext(Boy next) {
    26         this.next = next;
    27     }
    28 }

    2.2 编写CircleSingleLinkedList类

     1 /**
     2  * 创建一个环形的单向链表
     3  */
     4 public class CircleLinkedList {
     5     // 创建一个first节点,当前没有编号
     6     private Boy first = null;
     7     // 添加小孩节点,构成一个环形的链表
     8     public void addBoy(int nums) {
     9         // nums 做一个数据校验
    10         if(nums < 1) {
    11             System.out.println("nums 的值不正确");
    12             return;
    13         }
    14 
    15         Boy curBoy = null; // 辅助指针,帮助构建环形链表
    16         // 使用for来创建我们的环形链表
    17         for(int i = 1; i <= nums; i++) {
    18             // 根据编号,创建小孩节点
    19             Boy boy = new Boy(i);
    20             // 如果是第一个小孩
    21             if(i == 1) {
    22                 first = boy;
    23                 first.setNext(boy); // 够成环
    24                 curBoy = boy; // 让curBoy指向第一个小孩
    25             } else {
    26                 curBoy.setNext(boy);
    27                 boy.setNext(first);
    28                 curBoy = boy;
    29             }
    30         }
    31     }
    32 
    33     // 遍历当前的环形链表
    34     public void showBoy(){
    35         // 判断链表是否为空
    36         if (first == null) {
    37             System.out.println("没有任何小孩~");
    38             return;
    39         }
    40         // 因为first不能动,因此我们仍然使用一个辅助指针完成遍历
    41         Boy curBoy = first;
    42         while (true) {
    43             System.out.printf("小孩的编号%d 
    ", curBoy.getNo());
    44             if(curBoy.getNext() == first) {
    45                 break;
    46             }
    47             curBoy = curBoy.getNext(); // curBoy后移
    48         }
    49     }
    50 
    51     /**
    52      * 根据用户的输入,计算出小孩出圈的顺序
    53      * @param startNo 表示从第几个小孩开始数数
    54      * @param countNum 表示数几下
    55      * @param nums 表示最初优几个小孩在圈中
    56      */
    57     public void out(int startNo, int countNum, int nums){
    58 
    59         // 先对数据进行校验
    60         if (first == null || startNo < 1 || startNo > nums)
    61             System.out.println("参数输入有误,请重新输入~~");
    62         // 移动first
    63         for (int i = 1; i < startNo; i ++) {
    64             first = first.getNext();
    65         }
    66 
    67         Boy helper = first;
    68         // helper 移动到最后
    69         while (true) {
    70             if(helper.getNext() == first) {
    71                 break;
    72             }
    73             helper = helper.getNext(); // helper后移
    74         }
    75         // 循环出人
    76         while (true) {
    77             for (int i = 1; i < countNum; i ++) {
    78                 helper = helper.getNext();
    79             }
    80             // 出人
    81             System.out.printf("小孩的编号%d出圈
    ", helper.getNext().getNo());
    82             helper.setNext(helper.getNext().getNext());
    83 
    84             if(helper.getNext() == helper) {
    85                 System.out.printf("小孩的编号%d出圈
    ", helper.getNext().getNo());
    86                 first = null;
    87                 break;
    88             }
    89         }
    90     }
    91 }

    2.3 编写测试类Josepfu

     1 /**
     2  * 约瑟夫问题介绍
     3  *      Josephu 问题为:
     4  *      设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,
     5  *      数 到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,
     6  *      直到所有人出列为止,由 此产生一个出队编号的序列。
     7  */
     8 public class Josephu {
     9     public static void main(String[] args) {
    10         // 测试
    11         CircleLinkedList circleLinkedList = new CircleLinkedList();
    12         circleLinkedList.addBoy(5);
    13         circleLinkedList.showBoy();
    14 
    15         System.out.println("===============");
    16 
    17         circleLinkedList.out(1,2,5);
    18     }
    19 } 

    原文链接:https://blog.csdn.net/a1786742005/article/details/104059837

  • 相关阅读:
    VMdomainXml
    C 本地文件夸网文件Cp操作
    C++ auto 与 register、static keyword 浅析
    机器学习笔记——SVM
    NYOJ 298-点的变换(经典矩阵解决点平移、缩放、翻转和旋转)
    HDU 5407 CRB and Candies(LCM +最大素因子求逆元)
    Java总结之网络
    五月份小结
    算法——字符串匹配之BM算法
    javaweb_page指令
  • 原文地址:https://www.cnblogs.com/h--d/p/14556686.html
Copyright © 2020-2023  润新知