约瑟夫环:假如有n(n≥1)个人手拉手围在一起,从m(1≤m≤n)个人开始报数,最后一下报数的人出列,则出列的人的左右两边的人手拉手构成一个新的环状。
依次类推,直到最后一个人出列。
思路分析:先创建一个环形单向链表。每次添加节点的时候,永远将最后一个节点的next指针指向头结点。
创建指针curIndex指向头结点,curIndexPre指针永远指向curIndex的前一个元素。数count下,则这两个指针分别移动count-1次。
出列问题:指针curIndex最后停留的节点出列,然后curIndex = curIndex.next,目的是移动该指针到重组环后的最后一次停留的位置。
代码实现:
package dataStructureAtShangGuiGu; public class JosePhusDemo { public static void main(String[] args) throws InterruptedException { CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.add(4); sop("初始环状链表"); circleSingleLinkedList.list(); sop("报两次数出列顺序为:"); circleSingleLinkedList.outByCount(4,1,circleSingleLinkedList.size()); } private static void sop(Object obj) { System.out.println(obj); } } class CircleSingleLinkedList{ public Person first; public CircleSingleLinkedList() { this.first = new Person(-1,""); } public void add(int nums) { //生成一个环形单链表 Person cur = this.first; if(nums<1) { return; } for(int i=1;i<=nums;i++) { if(i==1) { this.first = new Person(i,"编号为"+i+"的男孩"); cur = this.first; continue; } cur.next = new Person(i,"编号为"+i+"的男孩"); cur = cur.next; cur.next = this.first; } cur = this.first; } public void list() { //显示环形链表元素 Person cur = this.first; if(cur.no==-1) { this.sop("[]"); return; } do { this.sop(cur); cur = cur.next; } while(this.first!=cur); } public void outByCount(int count,int startIndex,int maxSize) throws InterruptedException { //根据count报数出列 if(this.first==null||startIndex<1||startIndex>maxSize||count<1) { this.sop("参数有误!"); return; } Person curIndex = this.first; Person curIndexPre = this.first; while(curIndexPre.next!=this.first) { //将curIndexPre指针初始化到最后一个元素位置 curIndexPre = curIndexPre.next; }; for(int i=1;i<=startIndex-1;i++) { //分别移动curIndexPre、curIndex指针 curIndex = curIndex.next; curIndexPre = curIndexPre.next; } while(true){ for(int i=1;i<=count-1;i++) { //分别移动curIndexPre、curIndex指针 curIndex = curIndex.next; curIndexPre = curIndexPre.next; } this.sop(curIndex); //出列 if(curIndexPre==curIndex) break; curIndex = curIndex.next; curIndexPre.next = curIndex; Thread.sleep(1); } } public int size() { //获取环形链表长度 Person cur = this.first; int size = 0; if(cur.no==-1) return size; do { size++; cur = cur.next; } while(this.first!=cur); return size; } private void sop(Object obj) { //方便打印函数,正常显示方式 System.out.println(obj); } } class Person{ public int no; public String name; public Person next; public Person(int no,String name) { this.no = no; this.name = name; } public String toString() { return "[no="+this.no+",name="+this.name+"]"; } }
运行测试:
这里我定义了一个4个节点的单向环链表,从第一个节点开始数,每次数两下,出列编号顺序是 4 1 3 2 结果正确。