标签: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. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。