单向环形链表解决约瑟夫问题

约瑟夫问题:

设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,

数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

单向环形链表图示:

 代码:

  1 import lombok.Data;
  2 import org.junit.Test;
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 
  6 public class JosephusRingTest {
  7     @Test
  8     public void test() {
  9         RingSingleNode node1 = new RingSingleNode("小一");
 10         RingSingleNode node2 = new RingSingleNode("小二");
 11         RingSingleNode node3 = new RingSingleNode("小三");
 12         RingSingleNode node4 = new RingSingleNode("小四");
 13         RingSingleNode node5 = new RingSingleNode("小五");
 14         RingSingleLinkedList ringSingleLinkedList = new RingSingleLinkedList();
 15         ringSingleLinkedList.addNode(node1);
 16         ringSingleLinkedList.addNode(node2);
 17         ringSingleLinkedList.addNode(node3);
 18         ringSingleLinkedList.addNode(node4);
 19         ringSingleLinkedList.addNode(node5);
 20         System.out.println("最初链表~~~~~共" + ringSingleLinkedList.size() + "个");
 21         ringSingleLinkedList.show();
 22 
 23         List<RingSingleNode> result = ringSingleLinkedList.JosephusRing(1, 2);
 24         System.out.println(result);
 25         System.out.println("最终链表~~~~~共" + ringSingleLinkedList.size() + "个");
 26         ringSingleLinkedList.show();
 27     }
 28 }
 29 
 30 @Data
 31 class RingSingleNode {
 32 
 33     /**
 34      * 名称
 35      */
 36     private String name;
 37 
 38     private RingSingleNode next;
 39 
 40     public RingSingleNode() {
 41 
 42     }
 43 
 44     public RingSingleNode(String name) {
 45         this.name = name;
 46     }
 47 
 48     @Override
 49     public String toString() {
 50         return "RingSingleNode{" +
 51                 "name='" + name + '\'' +
 52                 '}';
 53     }
 54 }
 55 
 56 /**
 57  * 单向环形链表
 58  */
 59 class RingSingleLinkedList {
 60     /**
 61      * 链表的头部节点
 62      */
 63     private RingSingleNode first;
 64 
 65     /**
 66      * 链表的尾部节点
 67      */
 68     private RingSingleNode last;
 69 
 70     /**
 71      * 判断链表是否为空
 72      * @return
 73      */
 74     public boolean isEmpty() {
 75         return first == null;
 76     }
 77 
 78     /**
 79      * 添加节点
 80      * @param newNode
 81      * @return
 82      */
 83     public boolean addNode(RingSingleNode newNode) {
 84         if (isEmpty()) {
 85             //添加第一个节点
 86             first = newNode;
 87             newNode.setNext(newNode);
 88             last = newNode;
 89             return true;
 90         }
 91         newNode.setNext(first);
 92         last.setNext(newNode);
 93         last = newNode;
 94         return true;
 95     }
 96 
 97     /**
 98      * 获取链表的长度
 99      * @return
100      */
101     public int size() {
102         int count = 0;
103         if (isEmpty()) {
104             return count;
105         }
106 
107         RingSingleNode temp = first;
108         while (temp != last) {
109             count++;
110             temp = temp.getNext();
111         }
112         count++;
113         return count;
114     }
115 
116     /**
117      * 链表的遍历
118      */
119     public void show() {
120         RingSingleNode temp = first;
121         while (temp != last) {
122             System.out.println(temp);
123             temp = temp.getNext();
124         }
125         System.out.println(temp);
126     }
127 
128     /**
129      * 约瑟夫环
130      * @param k
131      * @param m
132      * @return
133      */
134     public List<RingSingleNode> JosephusRing(int k, int m) {
135         /*
136         设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,
137         数到m 的那个人出列,它的下一位又从1开始报数,
138         数到m的那个人又出列,依次类推,
139         直到所有人出列为止,由此产生一个出队编号的序列。
140          */
141         List<RingSingleNode> result = new ArrayList<>();
142         if (isEmpty()) {
143             System.out.println("链表为空,无法成环");
144             return result;
145         }
146 
147         if (k>=1 && k<=size() && m>=1) {
148             while (first != last) {
149                 //first移动(k-1)步到达编号为k的节点,last移动(k-1)步到达新的尾节点
150                 //报数之后,first和last一起走(m-1)步,first到达需弹出的节点,last则为弹出后的新的尾节点
151                 //即first,last一起总计走(k + m - 2)步
152                 for (int i = 0; i < k + m - 2; i++) {
153                     first = first.getNext();
154                     last = last.getNext();
155                 }
156                 //将指定节点弹出链表
157                 result.add(first);
158                 first = first.getNext();
159                 last.setNext(first);
160             }
161             //链表只剩最后一个节点
162             result.add(first);
163             first = null;
164             last = null;
165             return result;
166         }
167         System.out.println("m或k输入不合法");
168         return result;
169     }
170 }

 

posted @ 2023-01-13 14:46  Java厨师长  阅读(29)  评论(0)    收藏  举报