首页 > 其他分享 >约瑟夫问题--循环链表实现

约瑟夫问题--循环链表实现

时间:2022-11-17 22:33:27浏览次数:43  
标签:helper -- 报数 环形 约瑟夫 链表 节点 first

约瑟夫问题--循环链表实现

  • 问题:设编号为1、2...........n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它(m)的下一位又从1开始报数,数到m的那个人又出列,直到所有人出列为止,由此产生一个出队的编号的顺序
  • 设置:n是5,m是2,k是1,从第一个人开始报数。

单向环形链表实现

  • 构建一个单向的环形链表思路:

    1. 先创建第一个节点,让first指向该节点,并形成环形,即first.next=first
    2. 再每次创建一个新节点时就把该节点加入到已有的环形链表中即可
  • 遍历环形链表

    1. 先让一个辅助变量指针curBoy指向first节点

    2. 然后通过一个while循环遍历该环形链表即可

      • newBoyNodePre.next=newBoyNode;
      • newBoyNode.next=first;
      • curBoy=newBoyNodePre.next;或者curBoy=newBoyNode;
        • curBoy.next=first;则遍历结束

      代码实现

      1. 创建指定个数的环形链表和展示环形链表
      package com.guodaxia.josepfu;
      /**
       * @ author Guo daXia
       * @ create 2022/11/16
       */
      public class Josepfu {
          public static void main(String[] args) {
              CircleSingleLinkedList list = new CircleSingleLinkedList();
              list.addBoy(5);
              list.showBoy();
          }
      }
      /**
       * 创建一个单向循环链表
       */
      class CircleSingleLinkedList{
          //创建一个first节点
          private Boy first = null;
          //添加小孩节点,构建成一个环形的链表
          public void addBoy(int nums){
              if (nums<1){
                  System.out.println("nums不正确");
                  return;
              }
              //辅助指针,帮助遍历节点
              Boy curBoy = null;
              for (int i = 1;i<=nums;i++){
                  //根据编号,创建小孩节点
                  Boy boy = new Boy(i);
                  if (i==1){//如果是添加第一个小孩时,较为特殊
                      first=boy;
                      first.setNext(first);//boy的next为first,构成环。
                      curBoy=first;//让curBoy指向第一个小孩
                  }else {
                      curBoy.setNext(boy);
                      boy.setNext(first);
                      curBoy=boy;
                  }
              }
          }
          //遍历当前环形链表
          public void showBoy(){
              if (first==null){
                  System.out.println("没有任何小孩~");
                  return;
              }
              //因为first不能动,所以我们任然使用一个辅助指针进行遍历
              Boy curBoy = first; //从first第一个男孩开始遍历
              while (true){
                  System.out.printf("小孩的编号%d\n",curBoy.getNo());
                  if (curBoy.getNext()==first){break;}
                  curBoy= curBoy.getNext();//使辅助指针后移,达成循环迭代条件
              }
          }
      }
      /**
       * 创建一个Boy类,表示一个节点
       */
      class Boy{
          private int no;//编号
          private Boy next;//指向下一个节点,默认位null
          public Boy(int no) {this.no = no;}
          public int getNo() {return no;}
          public Boy getNext() {return next;}
          public void setNo(int no) {this.no = no;}
          public void setNext(Boy next) {this.next = next;}
      }
      
      1. 实现逻辑,按用户指定从那个小孩开始报数,直到报到 几下数结束,并将最后一个报数小孩出圈。
          /**
           * 根据用户输入,计算出小孩出圈的顺序
           * @param startNo 表示从第几个小孩开始报数
           * @param countNum 表示报几下
           * @param nums 表示初始人数有多少
           */
          public void countBoy(int startNo,int countNum,int nums){
              //先对数据校验
              if (first==null||startNo<1||startNo>nums){
                  System.out.println("无法玩!");
                  return;
              }
              //创建一个辅助指针 帮助完成小孩出圈
              Boy helper = first;
              //1.先让helper指向环形链表的最后一个节点
              while (true){
                  if (helper.getNext()==first){
                      break;
                  }
                  helper=helper.getNext();
              }
      
              //2.小孩报数前,先把helper和first移动startNo-1次(startNo是从第几个小孩开始报数)
              for (int i=0;i<startNo-1;i++){
                  first=first.getNext();
                  helper=helper.getNext();
              }
      
      
      
              while (true){
                  if (helper==first){//说明场上只剩一个小孩了
                      break;
                  }
                  //3.当小孩开始报数时,让helper和first指针同时移动countNum-1次(countNum是报几下)
                  for (int j=0;j<countNum-1;j++){
                      first=first.getNext();
                      helper=helper.getNext();
                  }
                  //4.这时就可以将first指针指向的小孩节点出圈,原来的first指向的节点就会被回收
                  System.out.printf("编号为%d的小孩出圈\n",first.getNo());
                  first=first.getNext();//first指针下移一位
                  helper.setNext(first);//将helper.next指向first
              }
              //跳出循环,可以把最后一个小孩节点打印出来、
              System.out.printf("场上剩下的最后一个编号为%d \n",helper.getNo());
          }
      }
      

标签:helper,--,报数,环形,约瑟夫,链表,节点,first
From: https://www.cnblogs.com/container-simple/p/16901268.html

相关文章

  • 在WPF中使用Prism弹出自定义窗体样式的对话框
    摘要在Prism中弹出一个对话框,默认是一个Windows默认样式的窗口,会与自己所开发的项目完全不搭配,例如下面这样子如果为了迎合软件主体风格,可以做出类似这样效果其实原理......
  • Java:SpringBoot整合hibernate-validator实现入参数据校验
    本文仅实现了api接口基本的参数校验,还有更多的校验场景,可以参考文章底部的参考链接使用starter创建SpringBoot项目,并添加依赖依赖<properties><java.version>1.8<......
  • #跟着小白一起学鸿蒙# [番外]一起学做FlappyBird
    #跟着小白一起学鸿蒙#[番外]一起学做FlappyBird作者:王石简介记得很久以前有个大火的像素游戏叫FlappyBird,我们就一起看看如何能用OpenHarmony学习做个FlappyBird。本文......
  • 运维必知必会的 Kubectl 命令总结,收藏好了~
    kubectl常用命令指南Kubectl命令是操作kubernetes集群的最直接的方式,特别是运维人员,需要对这些命令有一个详细的掌握Kubectl自动补全#setupautocompleteinbash,ba......
  • Spring数据访问和数据访问层与业务或服务层之间的交互
    版本6.0.0参考文档的这一部分涉及数据访问和数据访问层与业务或服务层之间的交互。Spring的全面事务管理支持已经详细介绍,然后全面涵盖各种数据访问框架和技术Spring框......
  • 用 Java 的 IO 流进行读写文件操作
    前言在计算机领域里IO,有时也写作​​I/O​​,是​​Input/Output​​的缩写,也就是输入和输出。这里的输入和输出是指不同系统之间的数据输入和输出,比如读写文件数据,读写......
  • 【MySQL】MySQL复制与高可用水平扩展架构实战
    本文导读本文简单介绍几种复制方式复制在生产中解决的实际问题,MySQL复制的配置流程和MySQL复制类型,不会深入到 MTBF、MTTR平均故障间隔、平均修复时间等等以及MMM集群架构......
  • 用了CDN就一定比不用更快吗?
    对于开发同学来说,CDN这个词,既熟悉又陌生。平时搞开发的时候很少需要碰这个,但却总能听到别人提起。我们都听说过它能加速,也大概知道个原因,但是往深了问。用了CDN就一定比不用......
  • 超标量处理器设计 电子书 pdf
    关注公众号:红宸笑。回复:电子书即可  ......
  • degit简介
    degit直接了当的脚手架!straightforwardproject scaffolding[ˈskæfəldɪŋ].安装npminstall-g degit使用degit复制git仓库。当运行degitsome-user/some-repo......