Java数据结构之单向环形链表解决约瑟夫问题

单向环形链表

最后一个节点的next指向第一个节点,形成一个环形(可以有头结点,也可以无头结点)
在这里插入图片描述

约瑟夫问题

Josephu(约瑟夫、约瑟夫环) 问题:
在这里插入图片描述
设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
举例:
在这里插入图片描述
先完成循环链表的构建:

package linkedlist;

public class Josephu {
	
	public static void main(String[] args) {
		//测试
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);//加入5个小孩
		circleSingleLinkedList.showBoy();
	}

}

// 创建一个环形链表类
class CircleSingleLinkedList {
	// 先创建一个first节点,当前没有编号
	private Boy first;

	// 添加小孩节点,构成一个环形链表
	public void addBoy(int nums) {
		// 对num进行校验
		if (nums < 1) {
			System.out.println("小孩数不正确");
			return;
		}
		//创建一个辅助变量
		Boy temp = null;
		//使用for来创建环形链表
		for(int i=1;i<=nums;i++) {
			//根据编号创建小孩节点
			Boy boy = new Boy(i);
			//如果是第一个节点
			if(i==1) {
				first = boy;
				boy.setNext(boy);
				temp = boy;
			}else {
				temp.setNext(boy);
				boy.setNext(first);
				temp = boy;
			}
		}
	}
	
	//遍历当前链表
	public void showBoy() {
		//判断链表是否为空
		if(first == null) {
			System.out.println("没有任何小孩");
			return;
		}
		//因为first不能动,所以我们需要一个辅助变量
		Boy temp = first;
		while(true) {
			System.out.println("小孩的编号为"+temp.getNo());
			if(temp.getNext() == first) {
				return;
			}
			temp =temp.getNext();
		}
	}
}

// 先创建一个Boy类,表示一个节点
class Boy {
	private int no;// 编号
	private Boy next;// 指向下一个节点

	public Boy(int no) {
		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;
	}
}

结果:

小孩的编号为1
小孩的编号为2
小孩的编号为3
小孩的编号为4
小孩的编号为5

小孩出圈思路:
在这里插入图片描述
代码:

public class Josephu {

	public static void main(String[] args) {
		// 测试
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();

		circleSingleLinkedList.countBoy(1, 2, 5);
	}

}

// 创建一个环形链表类
class CircleSingleLinkedList {
	// 先创建一个first节点,当前没有编号
	private Boy first;

	// 添加小孩节点,构成一个环形链表
	public void addBoy(int nums) {
		// 对num进行校验
		if (nums < 1) {
			System.out.println("小孩数不正确");
			return;
		}
		// 创建一个辅助变量
		Boy temp = null;
		// 使用for来创建环形链表
		for (int i = 1; i <= nums; i++) {
			// 根据编号创建小孩节点
			Boy boy = new Boy(i);
			// 如果是第一个节点
			if (i == 1) {
				first = boy;
				boy.setNext(boy);
				temp = boy;
			} else {
				temp.setNext(boy);
				boy.setNext(first);
				temp = boy;
			}
		}
	}

	// 根据用户输入,计算小孩出圈顺序
	/*
	 * startNo 表示从第几个小孩开始报数 
	 * countNum 表示数几下 
	 * nums 表示总共有几个小孩
	 */
	public void countBoy(int startNo, int countNum, int nums) {
		// 往环形链表添加nums个小孩
		addBoy(nums);
		// 先对数据进行校验
		if (first == null || startNo < 1 || startNo > nums) {
			System.out.println("参数输入有误,请重新输入");
			return;
		}
		// 先让first移动k-1次
		for (int i = 0; i < startNo - 1; i++) {
			first = first.getNext();
		}
		// 创建一个辅助变量
		Boy temp = first;
		// 将temp指向first前的小孩
		while (temp.getNext() != first) {
			temp = temp.getNext();
		}
		// 在小孩报数时,让temp和first同时移动countNum-1次,然后让first指向的小孩出圈
		while (temp != first) {// 当圈中只有一个小孩是,跳出循环
			// 让temp和first同时移动countNum-1次
			for (int i = 0; i < countNum - 1; i++) {
				temp = temp.getNext();
				first = first.getNext();
			}
			// 这时first指向的节点就是该出圈的小孩
			System.out.println("小孩" + first.getNo() + "出圈");
			// 删除该节点
			first = first.getNext();
			temp.setNext(first);
		}
		System.out.println("最终留在圈内的小孩编号为" + first.getNo());
	}
}

// 先创建一个Boy类,表示一个节点
class Boy {
	private int no;// 编号
	private Boy next;// 指向下一个节点

	public Boy(int no) {
		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;
	}
}

结果:

小孩2出圈
小孩4出圈
小孩1出圈
小孩5出圈
最终留在圈内的小孩编号为3
发布了30 篇原创文章 · 获赞 33 · 访问量 1255

猜你喜欢

转载自blog.csdn.net/weixin_45949075/article/details/105618986
今日推荐