约瑟夫环问题是,有n个人围成一个圆圈,任意给定一个正整数m,从第一个人开始依次报数,数到m时,则第m个人退出圆圈,重复进行,直至只剩下一个人为止,问最后剩下的是哪一个人?
求解方法:给n个人每人一个编号,将n个编号放在一个循环链表中,然后循环计数,每数到m,则删除相应数据元素结点(头节点跳过),删除过程执行n-1次,即完成求解。
package com.zl.test;
public class Node<T>{
public Object data;
public Node next;
}
package com.zl.test;
import com.zl.test.Node;
public class CirLink<T> {
private static Node head=null;
/**
* 初始化
*/
public void initCirLink(){
head=new Node();
head.data=null;
head.next=head;
}
/**
* 插入节点
* @param element :节点元素值
*/
public void insertCirLink(T element) {
Node node = new Node(); //初始化节点
node.data = element;
if (head.next == head) {
head.next = node;
node.next = head;
} else {
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = node;
node.next = head;
}
}
/**
* 值删除
*
* @param element : 要删除的值
* @return :删除则为true 否则为假
*/
public boolean deleteCirLink(T element) {
Node temp = head;
if (temp.next == head) {
System.out.println("链表已空,没有可删除的值");
return false;
}
while (temp.next != head) {
if (temp.next.data == element) {
temp.next = temp.next.next;
return true;
} else {
temp = temp.next;
}
}
return false;
}
/**
* 打印
*/
public void printCirLink() {
Node temp = head;
System.out.print("打印循环链表: ");
while (temp.next != head) {
temp = temp.next;
System.out.print(temp.data + " ");
}
System.out.println();
}
/**
* 求长度
*
* @return : 返回的长度
*/
public int sizeCirLink() {
Node temp = head;
int size = 0;
while (temp.next != head) {
temp = temp.next;
size++;
}
return size;
}
/**
* 下标删除
*
* @param i : 要删除的值下标
* @return :删除则为true 否则为假
*/
public boolean deleteIndexCirLink(int i) {
Node temp = head;
int index = -1;
if (temp.next == head) {
System.out.println("链表为空,没有可删除的值");
return false;
}
if (i < 0 || i >= sizeCirLink()) {
System.out.println("下标越界");
return false;
}
while (temp.next != head) {
index++;
if (index == i) {
temp.next = temp.next.next;
}
temp = temp.next;
}
return false;
}
/**
* 给定值求下标
*
* @param element :要找的元素
*/
public void findIndexByData(T element) {
Node temp = head;
int index = -1;
if (temp.next == head) {
System.out.println("链表为空,无法查找!");
}
while (temp.next != head) {
temp = temp.next;
index++;
if (temp.data == element) {
temp = temp.next;
System.out.println("下标为: " + index);
return;
}
}
System.out.println("要查找的值不存在!");
}
/**
* 下标求值
* @param index
*/
public void findDataByIndex(int index) {
Node temp = head;
int size= 0; //为增加下标用的
if (temp.next == head) {
System.out.println("链表为空,没有可查询的值!");
return;
}
if (index >= sizeCirLink() || index < 0){
System.out.println("下标越界");
return;
}
while (temp.next !=head){
temp = temp.next;
if (size == index){
System.out.println("要找的值为: "+temp.data);
return;
}
size++;
}
System.out.println("要查找的值不存在");
}
/**
* 下标求值
* @param index
*/
public Object getDataByIndex(int index) {
Node temp = head;
int size= 0; //为增加下标用的
if (temp.next == head) {
System.out.println("链表为空,没有可查询的值!");
return null;
}
if (index >= sizeCirLink() || index < 0){
System.out.println("下标越界");
return null;
}
while (temp.next !=head){
temp = temp.next;
if (size == index){
return temp.data;
}
size++;
}
return null;
}
}
package com.zl.test;
import com.zl.test.Node;
import com.zl.test.CirLink;
public class JosephusQuestion {
public static void josephus(int n ,int m){
//生成一个循环链表
CirLink<Integer> cirList=new CirLink();
//初始化
cirList.initCirLink();
//循环输入每个人的序号
for (int i=1;i<=n;i++){
cirList.insertCirLink(Integer.valueOf(i));
}
//从第targetIndex(数组下标)个开始重新数;
int targetIndex = 0;
while (cirList.sizeCirLink()!=1){
targetIndex = (targetIndex + m)%cirList.sizeCirLink();
if (targetIndex != 0) {//为0时为最后一个剩下来的人
System.out.println(cirList.getDataByIndex(targetIndex-1)+" 退出");
cirList.deleteIndexCirLink(targetIndex-1);
targetIndex--;
}else {
System.out.println(cirList.getDataByIndex(cirList.sizeCirLink()-1)+" 退出");
cirList.deleteIndexCirLink(cirList.sizeCirLink()-1);
}
}
//打印剩下来的人
System.out.println(cirList.getDataByIndex(0)+" 为最后剩下来的人 ");
}
public static void main(String[] args){
// n=12 m=5
josephus(12,5);
}
}
当12个人围成一圈,每次数到5的人退出,依次退出和最后剩下来的人见下:
5 退出
10 退出
3 退出
9 退出
4 退出
12 退出
8 退出
7 退出
11 退出
2 退出
6 退出
1 为最后剩下来的人