问题描述
Josephu问题:设编号为1,2,3…n的n个人围坐成一圈,约定编号为k的人从1开始报数,数到m的那个人出列,他的下一位从1开始报数,数到m那个人又出列,直到所有人都出列为止,由此产生一个出队列编号的序号。
解决方法
- 创建一个辅助指针helper,指向头指针的前一个节点
- 当小孩报数的时候,first指针和helper指针向后移 m-1 位
- 移动后进行出列,先将first指针后移一位,然后连接help指针
first = first.next
helper.next = first
代码部分
需要实现的功能
- 建立环形链表,通过输入数字n,确定要建立多少个人的环形链表
- 遍历打印环形链表
- 实现约瑟夫算法,输入m确定数几下出列
n=5(五个人)
k=1(从第一个人开始数)
m=2(数两下就出列)
package LinkList;
public class Josephu {
public static void main(String[] args) {
Josephu jDemo = new Josephu();
jDemo.josephu(5,1,2);
}
/**
* 约瑟夫算法
* @param n 环形链表中有多少小孩
* @param m 数几下进行出圈
* @param k 从第几个小孩开始报数
*/
public void josephu(int n, int k, int m)
{
CircleSimpleLinkList csl = new CircleSimpleLinkList();
Boy first = csl.CreateCircleLinkList(n);
Boy helper = csl.end;
//在开始之前需要移动到开始位置
for(int i=0; i<k-1; i++)
{
first = first.next;
helper = helper.next;
}
//数数到要出圈的男孩那,进行出圈
while(true)
{
if(helper == first)//到了最后一个人
{
break;
}
for(int i=0; i<m-1; i++)
{
first = first.next;
helper = helper.next;
}
//进行出圈
System.out.print(first.getNo() + "->");
first = first.next;
helper.next = first;
}
//输出最后一个男孩
System.out.println(first.getNo());
}
}
class CircleSimpleLinkList{
public Boy head = null;//指向头部
public Boy end = null;//指向尾部
//建立环形链表
public Boy CreateCircleLinkList(int no)
{
for(int i = 1; i <= no; i++)
{
Boy boy = new Boy(i);
//判断是否为头节点
if(i == 1)
{
head = boy;
end = boy;
end.next = head;
}else //不为头
{
end.next = boy;
end = boy;
end.next = head;
}
}
return head;
}
//遍历循环链表
public void showCircleLinkList(Boy head)
{
Boy sign = head;//标记
do{
System.out.print(sign.getNo() + "->");
sign = sign.next;
}while(sign != head);
}
}
class Boy{
private int No;
protected Boy next;
public Boy(int no)
{
this.No = no;
}
public int getNo() {
return No;
}
}