约瑟夫问题
数据结构——简单应用单链表
约瑟夫问题
Josephu 问题为: 设编号为1, 2, .. n的n个人围坐一圈,约定编号为k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
**提示**
: 用一个不带头结点的循环链表来处理Josephu问题: 先构成一个有 n个结点的单循环链表,然后由k结
点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直
到最后一个结点从链表中删除算法结束。
单向环形链表
约瑟夫问题分析图
代码实现分析 :
先创建一个单项环形链表
先创建第一个节点,让first指向该节点,并形成环形
后边当我们每创建一个新的节点,就把该节点,加到已有的环形链表中即可
遍历环形链表
先让一个辅助指针(temp),指向first
然后通过一个while循环遍历该链表即可 ( temp.next=first)遍历结束
这里有张图片:
生成小孩出圈的顺序
先创建一个辅助指针(helper),让它指向环形链表的最后一个
报数前,先让first和helper移动到startNo
当小孩报数时,让first与helper同时移动m-1次
这时first指向的小孩出圈
first=first.next
helper.next=first
此时原来first指向的节点就会被回收
这里有张图片:
创建节点的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Child { private int no; private Child next;
public Child ( int no ) { this.no = no; }
public int getNo ( ) { return no; }
public void setNo ( int no ) { this.no = no; }
public Child getNext ( ) { return next; }
public void setNext ( Child next ) { this.next = next; } }
|
创建环形链表的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class CireSingleLinkedList { private Child first = new Child ( -1 );
public void CreatChildList ( int nums ) { if ( nums < 1 ) { System.out.println ( "nums的值不正确" ); return; } Child temp = null; for ( int i = 1 ; i <= nums ; i++ ) { Child boy = new Child ( i ); if ( i == 1 ) { first = boy; first.setNext ( first ); temp = first; } else { temp.setNext ( boy ); boy.setNext ( first ); temp = boy; } } }
public void list ( ) { if ( first == null ) { System.out.println ( "链表为空,没有任何小孩\n" ); return; } Child temp = first; while (true) { System.out.printf ( "小孩的编号为%d\n", temp.getNo ( ) ); if ( temp.getNext ( ) == first ) { return; } temp = temp.getNext ( ); } } }
|
小孩出圈顺序代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
public void countBoy ( int startNo, int countNum, int nums ) { if ( first == null || startNo < 1 || startNo > nums ) { System.out.println ( "参数输入有误,请从新输入" ); return; } Child helper = first; while (true) { if ( helper.getNext ( ) == first ) { break; } helper = helper.getNext ( ); } for ( int j = 0 ; j < startNo - 1 ; j++ ) { first=first.getNext ( ); helper = helper.getNext ( ); } while (helper!=first) { for ( int j = 0 ; j < countNum - 1 ; j++ ) { first=first.getNext ( ); helper = helper.getNext ( ); } System.out.printf ( "小孩%d出圈\n", first.getNo ( ) ); first = first.getNext ( ); helper.setNext ( first ); } System.out.printf ( "最后留在圈中的小孩编号%d\n",first.getNo () ); }
|