环形链表-----约瑟夫环问题

目录

问题描述:

思路:

创建环时:

删除环中结点时:

完整java代码:

程序输出:


问题描述:

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

思路:

Josephu主要是创建环和删除环中结点的操作。

创建环时:

需要考虑头结点的记录,还要通过一个辅助指针不断往环中添加结点。

temp.next = node
temp = node

最后将最后一个结点指回头结点。

temp.next = head

删除环中结点时:

①在删除前,首先要将一个前驱指针指向环开始的前一个结点,(即环的最后一个结点),以方便删除时定位到待删除的前一结点。

while(pre.next != head) {
    pre = pre.next;
}

②再调整环的头结点和前驱结点,因为开始计数的第一个人可能不是创建环开始的那个人。调整时,需要将头结点和前驱节点移动目标编号减一的次数,使得头结点指向开始数数的那个人,前驱节点指向他的前一个结点。

for(int i = 1; i < start; i++) {
	pre = pre.next;
	head = head.next;
}

③计数,需要将头结点和前驱结点移动计数减一次,最终头结点指向待删除结点,前驱节点指向待删除的前一结点。此时可以输出待删除这一结点的信息。

④删除,将头结点后移,并将前驱节点指向后移后的头结点,实现“架空”待删除的结点。

head = head.next;
pre.next = head;

完整java代码:

public class JosephuDemo {
	public static void main(String[] args) {
		Josephu test = new Josephu(5, 2, 3);//环中5个人,从第2个人开始数,数至3的出圈
		System.out.println("环中5个人,从第2个人开始数,数至3的出圈");
		test.create();
		test.show();
		test.count();
	}
}

class Josephu{
	Node head = null;//头结点(只作引用,不创建对象)
	int total;//人总数
	int start;//开始数的起点
	int interval;//数数的间隔
	
	public Josephu(int total, int start, int interval) {
		this.total = total;
		this.start = start;
		this.interval = interval;
	}

	public void create() {
		Node temp = null;//辅助结点
		for(int i = 1; i <= total; i++) {
			Node node = new Node(i);
			if(i == 1) {
				head = node;//保留头结点
				temp = node;//记录辅助结点
			}else {
				temp.next = node;//将新结点连入辅助结点
				temp = node;//辅助结点后移
			}
		}
		temp.next = head;//最后一个结点连回头结点
	}
	
	public void show() {
		Node temp = head;//辅助遍历指针
		System.out.println("遍历环:");
		while(true) {
			if(temp.next == head) {//已经遍历到头结点(调整顺序可控制最后结点的输出位置)
				break;
			}
			System.out.print(temp.num + "->");//先输出当前指向的结点数据,再后移
			temp = temp.next;//后移
		}
		System.out.println(temp.num);
	}
	
	public void count() {
		Node pre = head;//指向环的最后一个结点
		while(pre.next != head) {
			pre = pre.next;
		}
		for(int i = 1; i < start; i++) {//调整头结点和pre(指向环的最后一结点位置)
			pre = pre.next;//最后pre指向开始计数的前一个人
			head = head.next;//最后head指向开始计数的人
		}
		System.out.println("出环的顺序:");
		while(pre != head) {//重合时,说明环中只剩一个结点
			for(int i = 1; i < interval; i++) {//后移interval - 1次
				pre = pre.next;//pre最后指向待删除的前一结点
				head = head.next;//head最后指向待删除结点
			}
			System.out.print(head.num + "->");//输出删除结点的信息
			head = head.next;//头结点后移
			pre.next = head;//辅助结点指向头结点(跳过了待删除结点)
		}
		System.out.println(head.num);//输出最后留在环中的结点信息
	}
}

class Node{
	int num;
	Node next;
	
	public Node(int num) {
		this.num = num;
	}
}

程序输出:

环中5个人,从第2个人开始数,数至3的出圈
遍历环:
1->2->3->4->5
出环的顺序:
4->2->1->3->5

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值