数据结构(五)-环形链表及约瑟夫问题

一、单向环形链表的应用场景(约瑟夫问题)

Josephu 问题为:设编号为1,2, ... n 的 n 个人坐成一圈,约定从编号为 k(n≥k≥1) 的人开始报数,数到 m 的那个人出列,她的下一位又从 1 开始报数,数到 m 的那个人又出列,以此类推,直到所有人出圈为止,因此形成一个出圈编号的序列

二、单向链表的示意图

三、创建环形链表图解

创建环形链表代码实现

// 创建单向环形链表
class SingleCircularLinkedList{
	
	// 初始化一个头节点
	Girl first = null;
	
	// 添加数据到链表中
	public void add(int num) {
		// 校验参数
		if(num < 1) {
			System.out.println("您输入的小孩个数小于1,不能创建环形链表");
		}
		// 定义临时指针
		Girl curGirl = first;
		for(int i = 1; i <= num; i++) {
			Girl girl = new Girl(i);
			
			if(i == 1) { // 说明是第一个节点
				first = girl;
				first.setNext(first);
				curGirl = first;
			}else {
				curGirl.setNext(girl);
				curGirl = girl; // curGirl 后移
				curGirl.setNext(first); // 形成闭环
			}
		}
	}
	
	// 遍历链表
	public void list() {
		// 判断链表是否为空
		if(first == null) {
			System.out.println("当前链表为空");
			return;
		}
		// 定义临时指针
		Girl curGirl = first;
		while(true) {
			System.out.printf("小孩编号为 %d 
", curGirl.getNo());
			if(curGirl.getNext() == first) {
				break;
			}
			curGirl = curGirl.getNext();
		}
	}
}

// 创建节点类
class Girl {

	private int no;
	private Girl next;

	public Girl(int no) {
		super();
		this.no = no;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public Girl getNext() {
		return next;
	}

	public void setNext(Girl next) {
		this.next = next;
	}
}

四、约瑟夫问题图解

补充,设置 helper 节点的思路来源于单向链表删除节点时,指针始终指在当前节点的前一位,cur.next = cur.next.next
代码实现

	// 约瑟夫问题
	public void joseph(int startNo, int countNum, int nums) {
		// 参数校验
		if(startNo < 1 || countNum > nums || nums < 1) {
			System.out.println("输入的参数有误");
			return;
		}
		// 定义临时指针
		Girl helper = first;
		// 让helper移动到first的上一个节点的位置,让first指针移动到startNo处(移动startNo - 1次)
		while(true) {
			if(helper.getNext() == first) {
				break;
			}
			helper = helper.getNext();
		}
		
		for(int i = 0; i < startNo - 1; i++) {

			first = first.getNext();
			helper = helper.getNext();
		}
		
		// 让first和helper同时移动countNum - 1次,小孩出圈
		while(true) {
			if(helper == first) { // 条件成立说明圈中只有一个小孩
				break;
			}
			for(int i = 0; i < countNum - 1; i++) {
				first = first.getNext();
				helper = helper.getNext();
			}
			// 小孩出圈操作
			System.out.printf("出圈的小孩为  %d 号
", first.getNo());
			first = first.getNext();
			helper.setNext(first);
		}
		// 输出圈中留下的lucky girl
		System.out.printf("留在圈中的 lucky girl 为  %d 号
", first.getNo());
	}
原文地址:https://www.cnblogs.com/wsilj/p/13689060.html