约瑟夫环

1、什么是约瑟夫环

     据说注明的犹太历史学家Josephus有过一下故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不抱被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,有第1个人开始报数,每个数到第3,该人就必须自杀,然后再有下一个人重新报数,知道所有人都自杀身亡为止。

     然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他讲朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。这就是约瑟夫自杀环的由来。

2、约瑟夫环求解

    建立一个有N个元素的循环链表,然后从链表头开始遍历并计数(周期为m),如果计数i==m,则号码出列,继续循环,当链表中的元素小于m时,则遍历链表。

package test.algorithm.FastSlowPointer;


public class Josephus {
	
	static class Node {
		private int num;
		private Node next;
		
		public Node(int num){
			this.num = num;
		}
	}
	
	/**
	 * 打印链表
	 * @param node
	 */
	static void printList(Node header){
		Node pointer = header.next;
		do{
			System.out.print(pointer.num+" ");
			pointer = pointer.next;
		}while(pointer!=null && pointer!=header.next);
		System.out.println();
	}

	public static void main(String[] args) {
		
		//头结点,声明一个链表(头结点值存储链表长度,不存储数据)
		Node header = new Josephus.Node(0);
		Node pointer = header;
		
		//初始化循环链表
		for(int i=1;i<=41;i++){
			pointer.next = new Josephus.Node(i);
			pointer = pointer.next;
			header.num = i;
		}
		pointer.next = header.next;
		printList(header);
		
		//自杀过程
		pointer = header.next;
		int i = 0;
		System.out.print("自杀顺序号:");
		//周期数
		int cycleNum = 3;
		// 如果链表长度大于等于周期数
		while(header.num>=cycleNum){
			i++;
			// 当i等于周期数-1时,即下一个号码就是要出列的号码
			// 为啥要周期数-1?因为该链表的节点只能找下一个
			if(i==(cycleNum-1)){
				// temp为要出列的号码
				Node temp = pointer.next;
				// 从链表中删除temp
				pointer.next = pointer.next.next;
				
				//如果删除的是链表的第一个节点,则header.next要指向第一个节点的next
				if(header.next==temp){
					header.next = temp.next;
				}
				// 链表长度更新
				header.num = header.num-1;
				// 已删除节点的next设置为空,方便垃圾回收
				// 防止已删除节点相互引用造成内存泄露
				temp.next = null;
				
				// 打印出列号码
				System.out.print(temp.num+" ");
				
				// 指针移动一位
				pointer = pointer.next;
				// 周期重新开始
				i=0;
			}else{
				pointer = pointer.next;
			}
		}
		
		//最后不够周期的两个号码,刚好是约瑟夫和他朋友的号码
		//他们不执行自杀规则的就不用死了
		System.out.println();
		System.out.print("幸存下来号码:");
		printList(header);
	}

}

你可能感兴趣的:(约瑟夫环)