约瑟夫问题升级版
题目:
- 编号为1~N的N个人按顺时针方向围坐一圈,每个人持有一个密码(正整数,可以自由输入),开始人选一个正整数做为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1报数,如此下去,直到所有人出列为止。
问题分析
和约瑟夫问题不同的是,升级版多了一个密码,这个密码可以从线性表导入,也就是在创建结点时,有三个区域密码域password、数据域位置position、指针域next。如下图所示
代码实现:
import DS01.动态数组.ArrayList;
//约瑟夫环升级版
public class Upper_JosephusLoop {
private Node head; //头指针
private Node rear; //尾指针
private int size; //未被淘汰的人数(相当于有效元素)
private int M; //报数的上限值
public Upper_JosephusLoop(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++){
//加结点 数据域从list里面拿,遍历的是位置,i给position结点的位置,指针域指向尾指针的下一个,也就是头
rear.next=new Node(list.get(i),i,rear.next);
rear=rear.next; //更新尾指针
}
size=list.getSize(); //人数是list传进来的个数
this.M=M;
}
//游戏淘汰函数
public void out(){
Node p=head; //创建指针p,游戏是从头指针处开始
while(size>0){
for(int i=1;i<=M-2;i++){ //由当前位置跳到M的前一个结点
p=p.next; //指针p移动
}
Node del=p.next; //del存放要删除的结点
p.next=del.next; //p所在结点的指针域指向del的下一个结点(删除del,没人指向del,del被回收)
p=p.next; //更新指针p
M=del.password; //根据题意,M更新
System.out.print(del.position+" "); //返回删除了的结点的位置
size--; //有效元素个数-1
}
}
//内部类
private class Node{
int password; //数据域
int position; //位置
Node next; //指针域
public Node(){}
public Node(int password,int position,Node next){ //密码(数据域),位置,指针域
this.password=password;
this.position=position;
this.next=next;
}
}
public static void main(String[] args) {
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);
Upper_JosephusLoop ju=new Upper_JosephusLoop(list,4); //M值初始给4
ju.out(); //调用游戏规则函数
}
}