約瑟夫問題(有時也稱爲約瑟夫斯置換,是一個出現在計算機科學和數學中的問題。在計算機編程的算法中,類似問題又稱爲約瑟夫環。又稱“丟手絹問題”.)
N個人圍成一圈,從第X個開始報數,第M個將被殺掉,最後剩下一個,其餘人都將被殺掉。
例如N=5,X=1, M=2,被殺掉的順序是:2 , 4 , 1 , 5 , 3
Java環形鏈表實現
1.模擬鏈表的 單個節點的數據結構
class Boy {
private int number; 小孩編號
private Boy next; 小孩下一位
public Boy(int number) {
this.number = number;}
public Boy getNext() {
return next;}
public void setNext(Boy next) {
this.next = next; }
}
2. 添加小孩並形成環
1 .定一個輔助 cur 指針 始終指向最新添加進來的小孩 2.當第一個小孩時,自己指向自己
3.當不是第一個時, 將 cur 的下一位指向新添加進來的 ,將新添加進來的 指向第一個形成環 , 將cur後移指向自己
public void add(int num) {
if (num < 1) {
System.out.println("數量太小!");
return;
}
Boy cur = null; //定一個輔助指針變量
for (int i = 1; i <= num; i++) {
if (i == 1) {
first = new Boy(1); //如果是第一個 就定義第一個小孩
first.setNext(first); //將自己指向自己
cur = first; //將當前指向first , 後面繼續使用
} else {
Boy boy = new Boy(i); //不是第一個,根據編號創建
cur.setNext(boy); //將當前指針的下一位指向,新來的
boy.setNext(first); //將新來的指向第一個,形成環
cur = boy; //將當前指向新來的 , 後面繼續使用
}}}
3.實現約瑟夫問題
1. 因爲是單向的環形鏈表,所以定一個輔助指針 helper 始終指向 cur 後面的一位
2.先讓 helper cur 同時移動 startNumber-1個 因爲數數自己也算一個
3.開始剔除時,結束條件 : cur== helper
4.數數時 helper cur同時移動 countNumber - 1 個 後 cur就是需要出圈的小孩
cur=cur.getNext(); 讓cur後移一位, 即下一位開始報數的人
helper.setNext(cur); 讓helper指向 出圈的小孩的下一個, 即下一位開始報數的人,就是讓當前first小孩出圈
5.first爲第一個加入的小孩
1.第一循環將helper 放在first 後面去 2.for循環將first, helper 同時移動 startnumber-1個,即從第幾個開始數
3.開始數數, 如果first==helper 說明到了最後一個結束循環 將first, helper 同時移動 countnumber-1個 ,first指向的爲出圈的
4.將first後移,將helper 指向新的first,即將舊的first出圈
public void ShowJosephProblem(int startNumber, int countNumber, int BoyNumbers) {
this.add(BoyNumbers);
if (startNumber < 1 || startNumber > BoyNumbers) {
System.out.println("參數非法");
return;
}
Boy helper = first; //先讓helper指向first 再循環使他指向最後一個
while (true) {
if (helper.getNext() == first) {
break;
}
helper = helper.getNext();
}
//讓first 指向 第一個開始數數的小孩
for (int i = 0; i < startNumber - 1; i++) { //因爲自己數算一個,所以是移動 countNumber-1個
helper = helper.getNext();
first = first.getNext();
}
//開始數數,
while (true){
if (first ==helper){ //因爲 helper 跟在後面 當最後一個小孩時他們相等
break;
}
//讓first,helper同時移動countNumber- 1個後 ,現在first 指向需要出圈的小孩,helper指向它的前一個
for (int i = 0; i < countNumber - 1; i++) {
first = first.getNext();
helper=helper.getNext();
}
System.out.printf("當前出圈小孩編號: %d \n", first.getNumber());
first = first.getNext(); //讓first後移一位, 即下一位開始報數的人
helper.setNext(first); //讓helper指向 出圈的小孩的下一個, 即下一位開始報數的人,就是讓當前first小孩出圈
}
System.out.printf("最後小孩編號: %d", first.getNumber()); }}