约瑟夫问题java语言解法
Josephu 问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此 产生一个出队编号的序列。
提示 :用一个不带头结点的循环链表来处理 Josephu 问题:先构成一个有 n 个结点的单循环链表,然后由 k 结点起从 1 开 始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从 1 开始计数,直到最后一个结点从链表中删除算法结束。
//节点定义
class Node{
int data;
Node next;
public Node(int data) {
this.data=data;
}
}
//问题处理
class Xunhuan_list{
Node first=null;
public void CreatNode(int t) {//创建一个 节点为i的循环链表
Node temp=null;
for(int i=1;i<=t;i++)
{
Node node=new Node(i);
if(i==1)
{
first=node;
first.next=first;
temp=first;
}else {
temp.next=node;
node.next=first;
temp=node;
}
}
}
public void printAll() {//遍历全部的节点
Node temp=first;
do {
System.out.print(temp.data);
if(temp.data!=5)
System.out.print("->");
if(temp.data==5)
System.out.println();
temp=temp.next;
}while(temp!=first);
}
public void Josepfu(int start,int num)//约瑟夫问题解决方案
{
Node helper=first;
while(helper.next!=first)//这里最开始出现的问题是 因为将helper!=first 所以导致helper 和 first 重合
{
helper=helper.next;//将协同指针指向在循环链表的最后一个节点上,也就是first的后面
}
for(int i=0;i<start-1;i++)//将两个指针同时移到起点和起点前
{
first=first.next;
helper=helper.next;
}
while(first!=helper)
{
for(int i=0;i<num-1;i++)
{
first=first.next;
helper=helper.next;
}
System.out.println("这次要去死的人是"+first.data);
first=first.next;
helper.next=first;
}
System.out.println("最后的幸存者为"+first.data);
}
}
- 下面利用主方法测试一下 总人数为5 人 每数到3就去死
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Xunhuan_list list=new Xunhuan_list();
list.CreatNode(5);
list.printAll();
list.Josepfu(1, 3); //这里输入的数据为 1 为从什么位置开始 3 是每叫到几就去死
}
}
运行结果如下
问题总结
- 关于循环链表的创建思路。
- 约瑟夫问题的解决算法
1.先创建一个helper 指针 ,将此指针指向first指针的前一个节点
然后 (如果是从第一个节点开始 那么就指向最后一个节点),每次数数m就跳跃m-1次,然后将first指针移动到出圈节点的下一个节点,然后将helper的next指针指向first,这样就实行了出圈,以此类推。
———————————————这将会是很好的一生!