其他解决方式:
Java中使用环形链表解决约瑟夫问题https://blog.csdn.net/qq_35813811/article/details/127159914
前言
众所周知,约瑟夫问题又名丢手绢问题,是一个经典的算法问题。这里就以丢手绢问题来模拟约瑟夫问题的大致内容。问题的大致内容是:已知n个小孩(以编号1,2,3.....,n)围成一个圈。从编号为k的人开始报数,数到m的那个人出列,出列之后,剩下的人又继续报数,同时他的下一个人又从1开始报数,数到m的那个人又出列,剩下的人又继续报数。以此规律重复下去,直到小孩全部出列。
该问题除了使用链表来解决,在Java中还可以使用 list来解决问题。
一、思路分析
在该问题的list解决方案中,我们已经不需要重新创建链表和Chird类来解决问题了,我们使用数字代替每一个小孩。
在这里,我们假设有6个小孩,我们选择使用两个中间变量来对list进行遍历,分别是point和a,point为list的下标,a为目前报数的数字。
开始之前,创建两个list集合,一个用于存放未出列的小孩,一个存放已经出列的小孩。由于下标是从0开始,k是从1开始,所以这里对point要为k-1,并且a的值为0.当开始报数时,point对应的list的下标就是1号小孩,同时将a增加1。报完数之后,point增加1,指向第二个下标的元素,同时a也增加。
当报到第三个小孩时,a等于m,3号小孩出列。此时就将3号小孩添加进已经出列的小孩列表。
添加成功之后,point继续增加,当报数到4号小孩时,a又重新变为1,当六号小孩报完之后,此时又将point归0,从1号小孩开始循环。
此时又会遇到一个问题,如果我又循环到已经添加过的小孩怎么办呢?
这个时候就需要判断这个小孩是不是在已经被添加过的列表中了,如果小孩在已经添加的列表中,则跳过小孩,继续向下循环,直到将最后一个小孩添加进已出列的list中,程序执行完成。
二、代码实现
import java.util.*;
public class ListSolveJosephu {
public static void main(String[] args) {
listSolveJosephu(6, 1, 3);
}
public static void listSolveJosephu(int n, int k, int m) {
//新建两个list
List<Integer> list = new ArrayList<>();
List<Integer> listFinal = new ArrayList<>();
//添加人数
for (int i = 0; i < n; i++) {
list.add(i+1);
}
int point = k-1;
int a = 1;
//开始循环
while (true) {
//如果已出列列表包含则point增加之后跳过
if (listFinal.contains(list.get(point))) {
point++;
if (point == list.size()) {
point = 0;
}
continue;
}
//如果a==m则向已出列list中增加元素
if (a == m) {
listFinal.add(list.get(point));
a = 0;
}
if (listFinal.size() == list.size()) {
break;
}
a++;
point++;
//如果point是list的长度之后,将point归零
if (point == list.size()) {
point = 0;
}
}
//打印输出的结果
for (int i = 0; i < listFinal.size(); i++) {
System.out.println(listFinal.get(i));
}
}
}
总结
这里利用了Java中的list解决了约瑟夫问题,相比起制作链表的方式简化了很多,可以看出在解决实际问题之时,Java的高灵活性。