约瑟夫问题(丢手绢问题)

/**
 * TODO 约瑟夫问题(丢手绢问题)
 * 
 * @author kakaluote
 * @date 2021年8月30日 下午3:57:05
 */
public class Josepfu {

	public static void main(String[] args) {
		
		CircleSingleLinkedList singleLinkedList = new CircleSingleLinkedList();
		singleLinkedList.addBoy(5);
//		singleLinkedList.showBoy();
		singleLinkedList.countBoy(1, 2, 5);
	}
}

//创建一个环形的单向链表
class CircleSingleLinkedList {
	private Boy first = null;
	
	//添加小孩节点,形成环形链表
	public void addBoy(int nums){
		if(nums < 1){
			throw new RuntimeException("nums 的值非法。");
		}
		//辅助变量,帮助我们构建环形链表
		Boy curBoy = null;
		for (int i = 1; i <= nums; i++) {
			Boy boy = new Boy(i);
			//如果是第一个小孩需要单独处理,自己指向自己
			if(i == 1){
				first = boy;
				first.setNext(first);
				curBoy = first;
			}else{
				curBoy.setNext(boy);
				boy.setNext(first);
				curBoy = boy;
			}
		}
	}
	
	/**
	 * 根据用户的输入,计算小孩出圈的顺序
	 * @param startNo 从第几个小孩开始数
	 * @param countNum 数几下
	 * @param nums 最初有多少小孩在圈中
	 */
	public void countBoy(int startNo,int countNum,int nums){
		if(first == null || startNo < 1 || startNo > nums){
			throw new RuntimeException("参数输入有误");
		}
		Boy helper = first;
		//helper 指向环形链表的最后一个节点
		while(true){
			if(helper.getNext() == first){
				break;
			}
			helper = helper.getNext();
		}
		//小孩报数前,先让first 和 helper 移动 k-1 次
		for (int i = 0; i < startNo - 1; i++) {
			first = first.getNext();
			helper = helper.getNext();
		}
		//当小孩报数时,让first 和 helper指针 同时移动m-1次,然后出圈
		//这里是一个循环操作
		while (true) {
			//说明圈中只有一个节点
			if(helper == first){
				break;
			}
			//让first 和 helper指针 同时移countNum-1次
			for (int i = 0; i < countNum - 1; i++) {
				first = first.getNext();
				helper = helper.getNext();
			}
			//这时first指向的节点,就是要出圈的小孩节点
			System.out.printf("小孩 %d 出圈 
",first.getNo());
			//这时将first指向的小孩节点出圈
			//first移动到first的下一个节点,也就是出圈孩子的下一个节点
			first = first.getNext();
			//helper 的next 指向新的first
			helper.setNext(first);
		}
		System.out.printf("最后留在圈中的小孩编号 %d 
",first.getNo());
	}
	
	//遍历当前环形链表
	public void showBoy(){
		if(first == null){
			System.out.println("链表为空");
			return;
		}
		//因为first不能动,需要一个辅助变量完成遍历
		Boy curBoy = first;
		while(true){
			System.out.printf("小孩的编号 %d 
",curBoy.getNo());
			//说明已经遍历完毕
			if(curBoy.getNext() == first){
				break;
			}
			//curBoy 后移
			curBoy = curBoy.getNext();
		}
	}
}

class Boy{
	private int no;
	private Boy next;
	public Boy(int no) {
		super();
		this.no = no;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Boy getNext() {
		return next;
	}
	public void setNext(Boy next) {
		this.next = next;
	}
}
原文地址:https://www.cnblogs.com/kaka-qiqi/p/15217657.html