【数据结构】环形链表

一、约瑟夫问题介绍    

  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

原文地址:https://www.cnblogs.com/h--d/p/14556686.html