ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

单向环形链表 —— 约瑟夫环问题

2019-09-25 10:03:39  阅读:226  来源: 互联网

标签:Boy helper 单向 约瑟夫 链表 public 节点 first


一、单向环形链表介绍

  

二、单向环形链表应用场景

  Josephu(约瑟夫、约瑟夫环) 问题

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

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

三、Josephu 问题

  1、约瑟夫的示意图

    

  2、Josephu 问题

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

  3、提示

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

  4、约瑟夫问题 — 创建环形链表的思路图解

     

  5、约瑟夫问题 — 小孩出圈的思路分析图

     

  6、代码实现

  1 package com.java.linkedlist;
  2 
  3 public class Josepfu {
  4 
  5     public static void main(String[] args) {
  6         // 测试
  7         // 构建环形链表
  8         CircleSingleLinkedList list = new CircleSingleLinkedList();
  9         list.addBoy(5); // 加入5个小孩节点
 10         list.showBoy();
 11 
 12         // 测试出圈
 13         list.countBoy(1, 2, 5);
 14 
 15     }
 16 
 17 }
 18 
 19 // 创建环形的单向链表
 20 class CircleSingleLinkedList {
 21     // 创建一个 first 节点,当前没编号
 22     private Boy first = null;
 23 
 24     // 添加小孩节点,构成一个环形的链表
 25     public void addBoy(int nums) {
 26         // nums 数据校验
 27         if (nums < 1) {
 28             System.out.println("nums的值不正确");
 29             return;
 30         }
 31 
 32         Boy curBoy = null; // 辅助指针,帮助构建环形链表
 33         // 使用for来创建环形链表
 34         for (int i = 1; i <= nums; i++) {
 35             // 根据编号,创建小孩节点
 36             Boy boy = new Boy(i);
 37             // 如果是第一个小孩
 38             if (i == 1) {
 39                 first = boy;
 40                 first.setNext(first); // 构成环
 41                 curBoy = first; // 让 curBoy指向第一个小孩
 42             } else {
 43                 curBoy.setNext(boy);
 44                 boy.setNext(first);
 45                 curBoy = boy;
 46             }
 47         }
 48 
 49     }
 50 
 51     // 遍历当前的环形链表
 52     public void showBoy() {
 53         // 判断链表是否为空
 54         if (first == null) {
 55             System.out.println("没有任何小孩");
 56             return;
 57         }
 58 
 59         // 因为 first 不能动,使用辅助指针完成遍历
 60         Boy curBoy = first;
 61         while (true) {
 62             System.out.printf("小孩的编号%d\n", curBoy.getNo());
 63             if (curBoy.getNext() == first) { // 说明已经遍历完毕
 64                 break;
 65             }
 66             curBoy = curBoy.getNext(); // 让 curBoy 后移
 67         }
 68     }
 69 
 70     // 根据用户的输入,计算出出圈的一个顺序
 71     /**
 72      * 
 73      * @param startNo  表示从第几个小孩开始数数
 74      * @param countNum 表示数几下
 75      * @param nums     表示最初有多少小孩在圈中
 76      */
 77     public void countBoy(int startNo, int countNum, int nums) {
 78         // 先对数据进行校验
 79         if (first == null || startNo < 1 || startNo > nums) {
 80             System.out.println("参数输入有误,请重新输入");
 81             return;
 82         }
 83 
 84         // 创建一个辅助指针,帮助完成小孩出圈
 85         Boy helper = first;
 86         // 需要创建一个辅助指针 helper,事先应该指向环形链表的最后这个节点
 87         while (true) {
 88             if (helper.getNext() == first) {
 89                 break;
 90             }
 91             helper = helper.getNext();
 92         }
 93 
 94         // 小孩报数前,先让 first和helper 移动k-1次
 95         for (int j = 0; j < startNo - 1; j++) {
 96             first = first.getNext();
 97             helper = helper.getNext();
 98         }
 99 
100         // 当小孩报数时,让first 和 helper 指针同时移动 m-1 次,然后出圈
101         // 循环操作,直到圈中只有一个节点
102         while (true) {
103             if (helper == first) { // 说明圈中只有一个节点
104                 break;
105             }
106             // 让 first 和helper 指针同时移动 countNum -1 次
107             for (int j = 0; j < countNum - 1; j++) {
108                 first = first.getNext();
109                 helper = helper.getNext();
110             }
111             // 这时first 指向的节点,就是要出圈的小孩节点
112             System.out.printf("小孩%d出圈\n", first.getNo());
113             // 这时将 first 指向 的小孩节点出圈
114             first = first.getNext();
115             helper.setNext(first);
116         }
117 
118         System.out.printf("最后留在圈中的小孩编号%d\n", first.getNo());
119     }
120 }
121 
122 // 创建一个Boy类,表示一个节点
123 class Boy {
124     private int no; // 编号
125     private Boy next; // 指向下一个节点,默认null
126 
127     // 构造方法
128     public Boy(int no) {
129         this.no = no;
130     }
131 
132     public int getNo() {
133         return no;
134     }
135 
136     public void setNo(int no) {
137         this.no = no;
138     }
139 
140     public Boy getNext() {
141         return next;
142     }
143 
144     public void setNext(Boy next) {
145         this.next = next;
146     }
147 
148 }

 

标签:Boy,helper,单向,约瑟夫,链表,public,节点,first
来源: https://www.cnblogs.com/niujifei/p/11582631.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有