Java数据结构与算法-Josephu约瑟夫问题(循环单链表实现)原理及代码实现

约瑟夫问题(循环单链表实现)原理及代码实现

循环单向链表学习目标

1. 循环链表的基本介绍及特点
2. 循环单链表的操作
3. 约瑟夫问题
4. 用循环单链表思路分析
5. 代码实现
6. 核心代码详解以及注意

一,循环单单链表的介绍及特点

在之前我们学习了单链表,循环单链表故名思意,首尾连接起来不就可以了?也即是最后一个节点的next指针指向头结点

二,循环单链表的操作

它和单链表一样就是插入删除遍历
插入:和单链表相似,除了尾节点插入需要把其next指向头结点。
删除:中间删除和单链表一样,末尾删除,先找到要删除元素的上一个元素(单链表无法对自身节点进行操作,都要借助前一位节点),然后把他的next指向头结点,删除的元素没有引用指向会被垃圾回收。
遍历:当最后一个节点的next指向头结点时,遍历结束。

三,约瑟夫问题

Josephu问题为:设编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
在这里插入图片描述
四,用循环链表进行分析解决的思路

1,先构成一个有n个结点的单循环链表
2,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除
3,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束

五,代码实现

package com.atxiaopeng.circlesinglelinkedlist;

public class CircleSingleLinkedList {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//
		CreateLinkList cL = new CreateLinkList();
		//cL.add(5);
		cL.getListOut(6, 2, 5);
		//cL.showList();
		
	}

}

class CreateLinkList{

	CreateNode first = null;
	
	public void add(int n) {

		CreateNode curr = null;
		if (n < 1) {
			System.out.println("数据有误!");
			return;
		}
		for (int i = 1; i <= n; i++) {
			
			CreateNode c = new CreateNode(i);

			if (i == 1) {
				first = c;
				c.next = first;
				curr = first;
			}else {
				curr.next = c;
				c.next = first;
				curr = curr.next;//指向c
				
			}
			
		}
		
	}
	
	public void showList() {
		
		if (first == null) {
			System.out.println("链表为空!");
			return;
		}
		CreateNode curr = first;
		while(true){
			if (curr.next == first) {
				System.out.println(curr.no);
				break;
			}
			System.out.print(curr.no+" ");
			curr = curr.next;
		}
		
		System.out.println();
		
	}
	//从链表中第K个元素开始数M个数循环取出元素
	public void getListOut(int k,int m,int num) {
		
		if (num == 0 || k<0 || k > num ||m < 0) {
			System.out.println("数据输入错误!");
			return;
		}
		add(num);
		CreateNode he = first;
		while (true) {
			if (he.next == first) {
				break;
			}
			he = he.next;
		}

		//报数前先让first和curr移动k-1个位置
		for (int i = 0; i < k-1; i++) {
			first = first.next;
			he = he.next;
		}


		System.out.print("出队列的元素顺序为:");
		while (true) {
			if (he == first) {
				break;
			}
			for (int i = 0; i < m-1; i++) {
				first = first.next;
				he = he.next;
			}
			System.out.print(first.no+" ");
			
			first = first.next;
			he.next = first;
		}
		
		System.out.println(he.no);
	}
	
	
}

class CreateNode{
	
	public int no;
	public CreateNode next;
	public  CreateNode(int n) {
		this.no = n;
	}
	
	
}

以上就是全部代码

六,总结

用循环单链表解决约瑟夫问题的核心代码:

CreateNode he = first;
		//第一次小循环
		while (true) {
			if (he.next == first) {
				break;
			}
			he = he.next;
		}
		//第二次小循环
		//报数前先让first和curr移动k-1个位置
		for (int i = 0; i < k-1; i++) {
			first = first.next;
			he = he.next;
		}


		System.out.print("出队列的元素顺序为:");
		//大循环
		while (true) {
			if (he == first) {
				break;
			}
			//大循环内部的小循环
			for (int i = 0; i < m-1; i++) {
				first = first.next;
				he = he.next;
			}
			System.out.print(first.no+" ");
			//出队列的操作
			first = first.next;
			he.next = first;
		}
		
		System.out.println(he.no);

分析

  1. 我们需要一个辅助节点,然后让他进行遍历,让它到链表的尾部并把它的next指向头结点first。
  2. 从第K个人开始报数,所以报数前,我们需要先把first节点的辅助节点同时移动k-1位。
  3. 然后开始报数,1到m,m出列,把first和辅助节点都移动m-1位,然后first出表,核心代码:first = first.next;辅助接点.next=first;
  4. 到最后当辅助节点 = first时,退出循环
  5. 总共一个大循环,里面包含了3中的小循环。而1循环是为了让辅助节点在链表的尾部,2循环是为了找到开始时的第k个人,同时把那个人当成first节点。这样就有点像是从K=1时第一个人开始的情形一样。
  6. 总而言之把要出链表的那个节点m当成first就行了,辅助节点始终指向first

欢迎指正,谢谢观看,仅供参考!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值