/*
* 环形链表【这里展示单环形链表】
* 无非就是每添加一个节点到最后。head节点的pre指向最后一个节点
* 或者是: 最后每添加一个节点的next域都会指向head节点
* 这里利用环形链表解决 约瑟夫问题::
* ---> 设有n的人围成一个环。约定编号为k(1<=k<=n)的人从1开始报数。数到m的那个人出列。出列的下一个人继续从k开始报数
* ---> 直到只有最后一个人。拿到由此产生的一个出列编号的 序列!
* n k m
* */
public class AnnualLinkedList {
public static void main(String[] args) {
ManagerAnnualNode ma = new ManagerAnnualNode();
int n=125;
//添加n个 人/数据
for(int i=1;i<=n;i++){
ma.addNode(new AnnualNode(i));
}
int[] arr=ma.ergodic(n,10,20);
for(int data:arr){
System.out.print(data+"-->\t");
}
}
}
/*
* 默认输入的数据遵守规则
* */
class ManagerAnnualNode{
final static Scanner sc=new Scanner(System.in);
private AnnualNode head=null;//第一个节点
private AnnualNode lastNode=null;//辅助指针
//环形添加 因为设定为是不带头节点的单向环形链表。所以要对它的第一个节点进行特殊处理
public void addNode(AnnualNode node){
if(head==null){
head=node;
head.next=head.next;//集成显示是自身给自身赋值 也可以head.next=node。但是我觉得这样写更加直观
}else {
//标记上一次节点的next域为添加的node
lastNode.next=node;
//最后一个节点永远指向head节点
node.next=head;
}
//标记每一次添加的节点。
lastNode=node;
}
//求出所有出来的顺序
public int[] ergodic(int n,int k,int m){
int[] arr=new int[n];
//找到从指定编号k的开始【因为是单向环形链表 所以要 是k-1的那一个编号 不然不好删除节点
AnnualNode kNode=first(k);
int count=1;
int index=0;
while (true){
//不管怎么样每循环一次都需要指向下一个节点
kNode=kNode.next;
count++;
//满足m条件表示该出链表了
if(count==m){
arr[index++]=kNode.next.id;
//从链表中删除已经出列的节点
kNode.next=kNode.next.next;
count=1;
}
//当只剩下一个数的时候就会成立这个条件
if(kNode==kNode.next){
arr[index++]=kNode.id;
break;
}
}
return arr;
}
//找到满足条件的前一个节点
public AnnualNode first(int id){
if(head==null){
System.out.println("没有数据可以遍历");
return null;
}
AnnualNode tmp=head;
// AnnualNode judge=head;
while (true){
if(tmp.next.id==id)break;
tmp=tmp.next;
// if(judge==head)throw new RuntimeException("不存在这个数据");//默认认为这个数一定存在
}
return tmp;
}
}
class AnnualNode{
int id;
AnnualNode next;
public AnnualNode() {}
public AnnualNode(int id) {
this.id = id;
}
}
记录