题目:
编号为1~N的N个人按顺时针方向围坐一圈,每个人持有一个密码(正整数,可以自由输入),开始人选一个正整数做为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报到M时 停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1报数,如此下去,直到所有人出列为止。
题目分析:
首先是约瑟夫环的大小是变化的,因此相应的结点也是变化的,我们使用链式存储结构可以动态的生成其中的结点,删除操作也非常简单。用单向循环链表对其进行出列顺序比较合适。
解题步骤:
首先需要输入参与的人数;
输入第一个密码;
把第一个人定为头结点。
代码(java实现):
package DS02.动态链表;
import DS01.动态数组.ArrayList;
/*
* 编号为1~N的N个人按顺时针方向围坐一圈,每个人持有一个密码(正整数,可以自由输入),
* 开始人选一个正整数做为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报到M时
* 停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1
* 报数,如此下去,直到所有人出列为止。
* */
public class JosephusLoopUpper {
private Node head;//头结点
private Node rear;//尾节点
private int size;//数组大小
private int M;//传入的第一个密码
public JosephusLoopUpper(ArrayList<Integer> list,int M){
head=new Node(list.get(0),0,null);
rear=head;
rear.next=head;//尾节点连接的头结点,形成循环链表
for(int i=1;i<list.getSize();i++){//遍历所有人
rear.next=new Node(list.get(i),i,rear.next);
rear=rear.next;//添加人进链表
}
size=list.getSize();
this.M=M;
}
public void out(){//删除人
Node p=head;
while(size>0){
for(int i=1;i<=M-2;i++){
p=p.next;
}
Node del=p.next;
p.next=del.next;
p=p.next;
M=del.password;
System.out.print(del.position+" ");
size--;
}
}
private class Node{
int password;//密码
int position;//位置
Node next;//要删除的节点
public Node(){}
public Node(int password,int position, Node next){
this.password=password;
this.next=next;//链表的下一个节点
this.position=position;
}
}
public static void main(String[] args) {//测试
//3 1 7 5 0 6 4 2
ArrayList<Integer> list=new ArrayList<>();
list.addLast(3);
list.addLast(5);
list.addLast(3);
list.addLast(6);
list.addLast(3);
list.addLast(2);
list.addLast(4);
list.addLast(4);
JosephusLoopUpper ju=new JosephusLoopUpper(list,4);
ju.out();
}
}