java实现约瑟夫问题

本文介绍了一种使用不带头结点的循环链表解决约瑟夫问题的方法。通过构建一个包含n个节点的单循环链表,从指定起点开始计数,每数到m则删除该节点,直至所有节点出列。文章详细展示了如何创建节点、构建链表、遍历及计数删除节点的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
在这里插入图片描述

public class Josephu {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		CircleSingleLinkedList circleSingleLinkedList =new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);	//加入5个节点
		circleSingleLinkedList.countBoy(1, 2, 5);
	}

}
//创建节点
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;
	}
}
class CircleSingleLinkedList{
	//创建一个first节点,当前没有编号
	private Boy first =new Boy(-1);
	//添加节点,形成环形链表
	public void addBoy(int nums) {
		if(nums<1) {
			System.out.println("nums值不正确");
			return;
		}
		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;	//让curBoy指向第一个小孩
			}else {
				curBoy .setNext(boy);
				boy.setNext(first);
				curBoy = boy ;
			}
		}
	}
	//遍历链表
	public void showBoy() {
		if(first ==null) {
			System.out.println("链表为空");
			return;
		}
		Boy curBoy =first;
		while(true) {
			System.out.printf("节点编号为%d\n",curBoy.getNo());
			if(curBoy.getNext()==first) {	//遍历完毕
				break;
			}
			curBoy =curBoy.getNext();//curBoy后移
		}
	}
	public void countBoy(int startNo,int countNum, int nums) {
		if(first ==null||startNo<1||startNo>nums) {
			return;
		}
		//创建辅助指针helper
		Boy helper =first;	
		while(true) {		//需要将helper指向最后一个节点
			if(helper.getNext()==first) {
				break;
			}
			helper =helper.getNext();
		}
		//报数前先让first和helper移动k-1次
		for(int j= 0;j<startNo-1;j++) {
			first =first.getNext();
			helper =helper.getNext();
		}
		//报数时first和helper同时移动m-1次,然后出圈
		while(true) {
			if(helper == first ) {	//说明圈中只有一个节点
				break;
			}
			//让first和helper移动m-1次
			for(int j =0;j<countNum-1;j++) {
				first =first.getNext();
				helper =helper.getNext();
			}
			System.out.printf("节点%d出圈\n",first.getNo());
			first =first.getNext();
			helper.setNext(first);
		}
		System.out.println("最后节点编号"+first.getNo());
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值