约瑟夫环 java_约瑟夫环的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 list = new ArrayList();

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 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.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;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值