java求解约瑟夫问题
作者:互联网
文章目录
前言
约瑟夫问题是数据结构中的经典算法题,这里使用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