ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java求解约瑟夫问题

2021-01-19 22:30:31  阅读:205  来源: 互联网

标签:Node java 求解 no next 出队 约瑟夫 preNode curNode


文章目录

前言

约瑟夫问题是数据结构中的经典算法题,这里使用java中的单向环形链表解决该问题。

一、问题描述

n个人围成一圈,每个人分别标注为1、2、…、n,要求从1号从1开始报数,报到m的人出圈,接着下一个人又从1开始报数,如此循环,直到剩余人数为0,输出出队序列。例如当n=25,m=12时,出队序列为12,24,11,25,14,3,18,8,1,19,13,7,5,4,6,10,17,23,20,16,22,21,15,9,2。给定n和m,请你输出出队序列。

二、解决思路

题目中描述了n个人围成一圈,所以我们可以使用java中的单向环形链表来模拟该结构,接着我们可以使用双层for循环来不断的数数与出队,直到出队完即可得到结果。

三、过程图解

在这里插入图片描述
当出队了1后,curNode就指向了下一节点2,preNode不变,还是curNode的前一节点,当2也出队了后,curNode和preNode就指向了同一节点,此时表示只剩下了最后一人,无需再数,直接出队即可

四、时间复杂度

使用单向循环链表求解的时间复杂度为O(n*m)。

五、代码实现

1.测试代码

代码如下:

package com.yc.linkedlist;

public class Josephu {
	public static void main(String[] args) {
		Josephu josephu = new Josephu();
		CircleSingleLinkedList circleLinkedList = josephu.new CircleSingleLinkedList();
		circleLinkedList.add(25);
		System.out.println("求解前");
		circleLinkedList.list();
		System.out.println("求解后");
		circleLinkedList.counter(1, 12, 25);
	}
	class CircleSingleLinkedList {
		private Node first;
		
		/**
		 * 单向循环链表,从no编号开始,不断数数与出队,直到全部人都出队
		 * @param no 从no编号开始数1
		 * @param m 出队数到m的那个人
		 * @param len 总共有多少人
		 */
		public void counter(int no,int m,int len){
			if(no<1||m<1||no>len||first==null){
				return;
			}
			//首先preNode和curNode都指向首节点,此处的首节点不是一般意义上的头节点,里面保存的是第一个人的编号,编号为1
			//curNode表示从哪个人开始数,当出队一人后,该节点就会指向出队那个人的下一人,表示从这个人开始重新数,进行新的一轮的判断
			//preNode表示不管curNode指向哪一个人,它始终指向curNode的前一个人,该节点用于辅助判断什么时候所有人都已出队
			Node preNode = first;
			Node curNode = first;
			while(true){
				//curNode不变,把preNode指向尾节点,因为是循环链表,所以此时preNode就可看成curNode的前一节点
				if(preNode.next == first){
					break;
				}
				preNode = preNode.next;
			}
			//根据参数no,调整preNode和curNode指向的位置
			for(int i=1;i<no;i++){
				curNode = curNode.next;
				preNode = preNode.next;
			}
			//循环数,直到所有人全部出队
			while(true){
				//终止条件,当人全部出队时执行该语句
				if(preNode == curNode){
					break;
				}
				//从1数到m,然后出队一人,此处的出队会直接丢弃出队那人的节点,然后preNode和curNode就都会发生相应的变化
				for(int i=1;i<m;i++){
					curNode = curNode.next;
					preNode = preNode.next;
				}
				System.out.print(curNode.no+" ");
				curNode = curNode.next;
				preNode.next = curNode;
			}
			System.out.print(curNode.no+" ");
			return;
		}
		/**
		 * 根据人数生成对应的单向循环链表
		 * @param num
		 */
		public void add(int num){
			if(num<1){
				return;
			}
			Node curNode = null;
			for(int i = 1;i <= num;i++){
				if(i==1){
					first = new Node(i);
					first.next = first;
					curNode = first;
				}else{
					Node newNode = new Node(i);
					curNode.next = newNode;
					newNode.next = first;
					curNode = newNode;
				}
			}
			return;
		}
		/**
		 * 打印输出节点
		 */
		public void list(){
			if(first==null){
				return;
			}
			Node curNode = first;
			while(true){
				System.out.print(curNode.no+" ");
				if(curNode.next==first){
					break;
				}
				curNode = curNode.next;
			}
			System.out.println();
			return;
		}
	}
	//单一节点
	class Node {
		private int no;
		private Node next;
		
		public Node(int no){
			this.no = no;
		}
		
		public Node(){
			
		}

		public int getNo() {
			return no;
		}

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

		public Node getNext() {
			return next;
		}

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

2.代码分析

代码分为三部分,测试代码,节点和单向循环链表,有兴趣的朋友可以测试查看结果。

总结

这是我用数据结构中的链表解决的第一个问题,还是很有收获,希望能和更多的朋友一起进步。

标签:Node,java,求解,no,next,出队,约瑟夫,preNode,curNode
来源: https://blog.csdn.net/qq_43567126/article/details/112851990

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有