Josephu, 约瑟夫, 约瑟夫环问题
设编号为1~n的n个人围坐到一圈, 约定编号为k(1<=k<=n)的人开始从1开始报数, 数到m的那个人出列, 它的下一位又开始从1开始数, 一次类推, 直到所有人都出列, 得到一个出列的序列.
分析
利用一个不带头结点的环形链表
创建一个不带头结点的环形链表
1.先创建一个节点, 并让frist指针指向该节点, 并形成环形
2.后面每新建一个新的节点, 就把该节点加入到已有的环形链表中去.
遍历环形链表
1.先让一个辅助指针cur指向第一个节点frist,
2.然后使用一个while循环遍历该环形链表,
3.直到当cur.next= frist结束.
解决问题的算法
1.需要创建一个last作为辅助变量, 实现指向最后一个节点, 当last== frist时就可以判断出是剩下最后一个
2.报数之前应先让frist和last同时移动k-1次, 到达一开始的报数位置
3.报数时, 让frist和last同时移动m-1次
4.这时frist指向的节点就可以出圈
5.frist指向下一个再开始报数, 出圈的这个节点没有被引用, 就会被回收
public class Josephu {
public static void main(String[] args) {
Ringsinglerlinkedlist rsll = new Ringsinglerlinkedlist();
rsll.create(5);
rsll.show();
rsll.showJosephu(1,2,5);
//rsll.show();
}
}
class Ringsinglerlinkedlist {
private Boy frist = null;
//传入一个int值, 创建一个int值个数的单向环形链表
public void create(int count){
if (count < 1){
System.out.println("节点的个数直少有一个");
return;
}
Boy cur = null;
for (int i = 1; i <= count; i++){
Boy boy = new Boy(i);
if (i == 1){
frist = boy;
frist.next = frist;
cur = frist;
}else{
cur.next = boy;
boy.next = frist;
cur = boy;
}
}
}
//遍历单向环形链表并打印
public void show(){
if (frist == null){
System.out.println("这个单向环形链表为空");
return;
}
Boy cur = frist;
while(true){
System.out.print(cur);
if (cur.next == frist){
break;
}
cur = cur.next;
}
System.out.println();
}
//约瑟夫问题的出列序列
public void showJosephu(int k, int m, int count){
if (k < 1 || k > count || frist == null){
System.out.println("链表是空或者开始位置有误~ ");
}
Boy last = frist;
while(true){
if (last.next == frist){
break;
}
last = last.next;
}
for (int i = 1; i<= k-1; i++){
frist = frist.next;
last = last.next;
}
while(true){
if (last == frist){
System.out.println(frist);
break;
}
for (int j = 1; j <= m-1; j++){
frist = frist.next;
last = last.next;
}
System.out.println(frist);
last.next = frist.next;
frist = frist.next;
}
}
}
class Boy{
public int number;
public Boy next;
public Boy(int number){
this.number = number;
}
@Override
public String toString() {
return "Boy{" +
"number=" + number +
'}';
}
}