Josephu问题为:
设编号为1, 2, …n的n个人围坐一圈,约定编号为k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
package 链表; public class JosePhu问题 { public static void main(String[] args) { CircleLinkedList circleLinkedList = new CircleLinkedList(); circleLinkedList.addBoy(5); //此时环形链表有五个节点 circleLinkedList.list(); circleLinkedList.countBoy(1,2,5); } } class CircleLinkedList{ private Boy first = null; //初始头节点 //构建指定长度的环形链表 public void addBoy(int num){ Boy cur = null; //用来遍历的辅助指针 for(int i=1;i<=num;i++){ Boy boy = new Boy(i); if(i==1){ //第一次构建需要自身指向自身 first = boy; first.next = first; cur = first; } else{ cur.next = boy; //将新建立的节点加入环形链表中,此时cur的位置就是原先创建的环形链表的尾端 boy.next = first; //将添加进来的新节点的尾部指向头节点,形成环状 cur = cur.next; //cur每次要移动到尾部 } } } //按照添加顺序显示环形链表 public void list(){ if(first==null){ System.out.println("环形链表为空"); return; } Boy cur = first; //用来遍历的临时指针 while(true){ System.out.println(cur.num); //先打印 if(cur.next==first){ //如果其next指向头指针,则代表遍历完全 return; } cur = cur.next; } } /* * startNo 表示从第几个小孩开始数数 * countNum 表示数几下 * nums 表示最初有多少小孩在里面 * 这个是用来解决约瑟夫问题的方法,即指定小孩人数,第一次报数从哪个小孩开始,每数到几让谁出来 后,我们使用环形链表来模拟出队顺序 * */ public void countBoy(int startNo,int countNum,int nums){ /* * 其实可以不用两次循环,使用一次循环来解决,即first向前移动时,help跟着移动,只不过移动的要比first少1即可; * 但是这样的话对于countNum为0时则不行 * */ Boy help = first; //辅助指针,指向头指针的前一个位置 /*因为我们下面是设置头指针直接移动到我们要出队的节点,而又由于我们是一个单向环形队列,所以头指针位置要出队,那么我们 为了保存头指针位置,只能从头指针的前一个位置得到,所以我们设置辅助指针的目的就是为了通过其的next指针来得到删去的 头指针位置!!!! 所以其实这个也可以不设置,不过设置了会更加清晰*/ //先将辅助指针移动到尾部,因此此时头指针在头部,所以刚好形成前后关系 while(true){ if(help.next==first){ break; } help = help.next; } //因此从第startNo个小孩开始报数,所以头指针的实际位置需要改变 for (int i=0;i<startNo-1;i++){ first = first.next; help = help.next; //help是头指针的前一个,所以也跟着动 } //模拟报数出队,直到全部出完 while(true){ for (int i=0;i<countNum-1;i++){ //先报数,即头指针先移动到指定要出队的节点的位置 first = first.next; help = help.next; //辅助指针跟着移动 } System.out.println(first.num); //找到要出队的了 if(help==first){ //如果两个指针重合,则一定代表就剩下一个了,因为一个指针的下一个指针指向自己了! break; } first = first.next; //将头指针此时指向的位置删除,并指向自己原先位置指向的的下一个位置 help.next = first; //将被删除的节点的上一个节点的next指向设置为删除位置的下一个位置 , 这样才起到删除作用 } } } class Boy{ int num; Boy next; public Boy(int num) { this.num = num; } public Boy() { } }