约瑟夫环的java解决

总共3中解决方法,1、数学推导,2、使用ArrayList递归解决,3、使用首位相连的LinkedList解决

import java.util.ArrayList;

/**
* 约瑟夫环问题
* 需求:n个人围成一圈,从第一个人开始报数,数到K的人出局,然后从下一个人接着报数,直到最后一个人,求最后一个人的编号
* @author Miao
*
*/
public class Josephus {
public static void main(String[] args) {
int n = 13;
int k = 3;
int last;
// last =getLast(n,k); //使用数学推导求结果
/* 使用递归求结果
* ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 1; i <= n; i++) {
list.add(i);
}
last = getLast(list, k,0); //从下标为0开始报数,
*/
// System.out.println(last);
/**
* 使用链表方式求结果,链表为头尾相接的环形链表
*/

MyLinkedList list = new MyLinkedList();
for (int i = 1; i <= n; i++) {
list.add(i);
}
//只要链表中元素个数大于1个,则指向下面步骤
while(list.length>1){
Node temp = list.first; //获得头节点
//将temp节点从头节点向后挪k个位置
for (int i = 1; i < k; i++) {
temp = temp.next;
}

System.out.println("被移除的编号为:"+temp.value);
list.remove(temp); //移除当前temp位置的节点
System.out.println("剩余元素为:"+list.toString()+",长度为"+list.length);
}
//当上面循环结束时,链表内只剩1个元素
last = list.first.value;
System.out.println(last);
}
/**
* 数学推导,已知圈内只有一个人时候,剩余的是编号1,根据推导,如果当圈内有n-1个人时剩余的人编号为last,
* 那么当圈内有n人时,剩余的人的编号是last+k,因为可能last+k以后大于了当前圈内人数,所以剩余的
* 人的编号为(last+k)%n,但这时就会出现如果last+k后指向最后一个人,这时得到的编号为0,不符合要
* 求,所以用((last+k-1)%n)+1,这样最后一个人报的数也是自己了,而其他位置的人报数不变。
*
* @param n 圈内人数
* @param k 数到该数字的人出局
* @return 剩余人的编号
*/
public static int getLast(int n , int k){

int last = 1; //这是初始值,即环内为1个人时剩余的人的编号,必然为1,也是后面推导的基础
//System.out.println("当环内有1个人时,剩余的是:1");
for (int i = 2; i <= n; i++) { //当圈内为i个人时,结果是圈内为i-1个人的结果加K后对i求余
last = ((last + k - 1) % i) + 1; //为避免出现结果为0,让i-1的结果先减1,求余后再加1
//System.out.println("当环内有" + i + "个人时,剩余的是:" + last);
}
return last;
}

/**
* 递归方式:第一轮根据传入的集合、开始下标和间隔求出第一轮出局的人的下标,然后将该人移出集合,
* 并求出下一轮的开始下标,然后迭代调用本方法,将剩余集合元素和新的开始下标传入计算,
* 直至剩余最后一个元素,就是最后存货的元素
* @param list 传入的集合
* @param k 报数到K的人出局
* @param m 从下标为m的人开始报数
* @return 剩余最后一个人的编号
*/
public static int getLast(ArrayList<Integer> list, int k , int m){
int last = -1; //用来放置最后一个人的编号
int index = -1; //用来放置当前一轮被移除的人的下标
if (list.size() == 1) { // 如果集合内只剩一个元素,则直接返回该元素作为结果
last = list.get(0);
} else {
index = (m + k - 1) % list.size(); // 求出当前一轮被移除的人的下标
/* System.out.println("当前集合内的元素为:" + list.toString());
System.out.println("从" + list.get(m) + "开始报数,被移除的是:"
+ list.get(index));*/
list.remove(index); // 将该人移除
m = index % list.size(); // 求出新一轮报数时开始的人在新集合里的下标
last = getLast(list, k, m); // 使用剩余的集合和m的位置重新开始下一轮计算
}
return last;
}

}

/**
* 定义一个双向节点类,用作实现链表功能
* @author Miao
*
*/
class Node{
Integer value;
Node next;
Node prev;
public Node(){
value = null;
prev=null;
next = null;
}
public Node(Integer value){
this.value = value;
next = null;
prev = null;
}
public String toString(){
return this.prev.value+"<"+this.value+">"+this.next.value;
}
}
/**
* 定义自己的双向链表类,用来放置数据
* @author Miao
*
*/
class MyLinkedList{
public Node first;
public Node last;
public int length;
public MyLinkedList(){
first = new Node();
last = first;
length = 0;
}
//在链表结尾增加元素的方法
public void add(Integer i){
if(length == 0){
first.value = i; //添加第一个元素,只需要设置该元素的value
}else{
Node temp = new Node(); //添加元素时,1、新建一个元素,
temp.value = i;
temp.prev = last; //2、然后先与last节点建立双向关系,
last.next = temp;
first.prev = temp; //3、再与first节点建立双向关系,
temp.next = first;
last = temp; //4、最后让last指向该节点,3、4步可颠倒
}

length++;
}
//从链表中删除指定节点的方法
public void remove(Node node){
node.prev.next = node.next; //将前节点的next跳过本节点,指向下个节点
node.next.prev = node.prev; //将后节点的prev跳过本节点,指向前节点 ,此时该节点已经从链表中移除了
this.first = node.next; //指定后节点为头节点
this.last = node.prev; //指定前节点为尾节点
node = null;
length--;
}

public String toString(){
String str ="[";
Node temp = first;
for (int i = 1 ; i < length; i++ ) {
str += temp.value+",";
temp = temp.next;
}
str += (temp.value+"]");
return str;
}

}

时间: 2025-01-17 00:43:24

约瑟夫环的java解决的相关文章

约瑟夫环问题-Java数组解决

约瑟夫环问题说的是,n个人围成一圈,从第k个人开始沿着一个方向报数,报到第m个人时,第m个人出列,从紧挨着的下一个人(未出列)开始,求整个环中人的出列顺序.下面是我用java实现的解决方法. 1 class JosephLoop 2 { //n为环中人数,m为每次报数的人数,k为报数的起始位置0-n 3 int n,m,k; 4 int[] persons; 5 int[] seq; 6 7 JosephLoop(int n, int k, int m){ 8 this.n = n; 9 thi

约瑟夫环 --- 面向对象 --- java代码

约瑟夫环 的 面向对象 解法 罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏. 如有疑问请参考:http://blog.fishc.com

经典例题|约瑟夫环多方法解决

本文章将用循环链表.数组.递归以及循环方法对约瑟夫环问题进行讲解.其中链表法和数组法会对过程进行模拟,递归和循环将对约瑟夫环问题进行数学剖析. 问题描述 n个人围成圈,依次编号为1.2.3.....n,从1号开始依次报数,当报到m时,报m的人退出,下一个人重新从1报起,当报到m时,报m的人退出,如此循环下去,问最后剩下的那个人的编号是多少? 链表法 建立一个循环链表,节点的数值部分存储整数1至n,将尾部节点链接到第一个节点,每次遍历m-2步,把第m-1个节的指针域指向的节点数据打印出来,然后将m

约瑟夫环问题 java代码实现(高效率)

问题来历编辑 据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.然而Josephus 和他的朋友并不想遵从.一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是

Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)

1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列. 提示: 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法

j使用数组实现约瑟夫环 java

我们首先来看一下约瑟夫环问题: 给定m个人,m个人围成一圈,在给定一个数n,从m个人中的第一个人每第n个人便将其除去,求被最后一个出去的人的编号. 思路: 建立一个长度为m+1的数组,将其的内容初始化为0至m 我们设置变量i与j,i代表数组元素的下表,因为我设置的数组长度为m+1,所以数组下标就为每个人的编号,当i==m的时候,我们将i置为0,让其从头开始便利. 变量j为判断当前元素是否为排列的第n个元素,如果是则将当前下标为i的元素的值置为0,不是的话,i++,j++,每当我们遍历到数值为0的

C++ 用循环链表解决约瑟夫环问题

约瑟夫环问题 已知 n 个人(n>=1)围坐一圆桌周围,从 1 开始顺序编号,从序号为 1 的人开始报数,顺时针数到 m 的那个人出列.下一个人又从 1 开始报数,数到m 的那个人又出列.依此规则重复下去,直到所有人全部出列.请问最后一个出列的人的初始编号. 要求 输入人数 n,所报数 m,输出最后一个人的初始编号. 解决思路 首先因为是圆桌问题,使用链表解决的话需要构建循环链表. 接着是出列问题,这里我的设计思路是将指向链表的指针移动到需要出列的人的位置,然后根据正常的链表删除进行操作即可.

C++循环链表解决约瑟夫环问题

约瑟夫环问题可以简单的使用数组的方式实现,但是现在我使用循环链表的方法来实现,因为上午看到一道面试题规定使用循环链表解决约瑟夫环问题. 什么是约瑟夫环? “约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周围的人全部出列.”(百度百科中的解决办法列出了很多,可以看到循环链表并不是最简单的方法) 这道面试题考察了循环链表的“创建”,

约瑟夫环 java实现

问题: N个人从1到N编号,围城一圈,从1开始报数, 数到X时,将X的编号输出,并将那个人踢出, 下一个从1再开始报数,直到所有人都出去 思路: 就是计数,移除,没有太深的思想,直接上代码: package test; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * N个人从1到N编号,围城一圈, * 从1开始报数, 数到X时,将X的编号输出,并将那个人踢出, * 下一个从1再开