约瑟夫环:设编号为 1 ~ n( n > 0 )的 n 个人按顺时针方向围成一圈,约定编号为 k 的人从 1 开始顺时针报数,报 m 的人( m 为正整数),令其出列。然后从他的下一个人开始,重新从 1 顺时针报数,报 m 的人,再令其出列,如此下去,直到圈中所有人都出列为止。求出列编号序列。
public class CycleList {
public static Boy first = null;
public static void main(String[] args) {
// Scanner sc = new Scanner(System.in);
// int n = sc.nextInt();
createCycleList(10);
showList();
joseph(1,10,3);
}
//构建环形链表
public static void createCycleList(int n) {
if (n < 1) {
System.out.println("输入的人数不能构建环形链表");
return;
}
Boy curBoy = null;//辅助指针
for (int i = 1; i <= n; i++) {
Boy boy = new Boy(i);
if (i == 1) {
first = boy;
first.next = first;//形成环形链表
curBoy = first;
} else {
curBoy.next = boy;
boy.next = first;
curBoy = boy;
}
}
}
//遍历
public static void showList() {
Boy cur = first;
while (cur.next != first) {
System.out.println("小孩的编号为:"+cur.id);
cur = cur.next;
}
System.out.println("小孩的编号为:"+cur.id);
System.out.println();
}
//解决约瑟夫环
//k:从哪个编号开始 n:总人数 m:叫号
public static void joseph(int k,int n,int m) {
if (first == null || k < 1 || k > n) {
System.out.println("数据不合法");
return;
}
//找到开始编号的先驱节点(2步)
Boy pre = first;
while (pre.next != first) {
pre = pre.next;
}
//现在的pre节点就是first的先驱节点
//将first指针移动到k的位置上,pre移到k的先驱节点(移动k-1步)
int count = k-1;
while (count != 0) {
first = first.next;
pre = pre.next;
count--;
}
while (true) {
if (pre == first) {
//说明圈中只剩下一个人了
break;
}
for (int i = 0; i < m-1; i++) {
pre = pre.next;
first = first.next;
}
System.out.println("小孩的编号为:"+first.id);
first = first.next;
pre.next = first;
}
System.out.println("小孩的编号为:"+pre.id);
}
}
class Boy {
public int id;//小孩编号
public Boy next;
public Boy(int id) {
this.id = id;
}
}