Josephus問題求解:
設有n個人圍坐一個圓桌周圍,,現從第k人開始報數,數到第m的人出列,
然後從出列的下一個重新開始報數,數列的第m個人又出列……如此重複,直
到所有的人全部出列爲止。對任意給定的n、k、m,求按出列次序得到的n個
人員的順序表。
(這個問題看別人用C以數學算法與遞歸法寫出來,代碼不過幾行,我這上百行的代碼確實有點汗顏)
續:算法優化——在每次數到m-1下時,保存當時那個對象的.nextPeron,就不用再重新去找被刪除對象的前一個對象了,這裏不再修改了。
import java.util.Scanner;
class Person{
int no;
Person nextPerson = null;
public Person(int no){
this.no = no;
}
}
class CycleLink{
Person firstPerson = null; //指向鏈表第一個人的引用
int len; //定義鏈表長度
Person temp = null;
int k = 0;
int m = 0;
//設定鏈表長度
public void setLen(int len){
this.len = len;
}
//從第幾個人開始數
public void setK(int k){
this.k = k;
}
//每次數幾下
public void setM(int m){
this.m = m;
}
//創建鏈表
public void createLink(){
for(int i=1; i<=len; i++){
Person p = new Person(i);
//環鏈的第一個對象
if(i==1){
this.firstPerson = p; //將第一個對象的引用存放在firstPerson中
this.temp = p; //將第一個對象的引用暫時賦於temp,用於接收下一個對象的引用
}
//環鏈的最後一個對象
else if(i==len){
this.temp.nextPerson = p; //將最後一個對象的引用賦給倒數第二個對象的nextPerson
temp = p; //將當前對象(也就是最後一個對象)的引用暫賦給temp
temp.nextPerson = this.firstPerson; //將第一個對象的引用賦給最後一個對象的nextPerson
}else{
this.temp.nextPerson = p;//將當前對象的引用賦給上一個對象的引用變量nextPerson中
this.temp = p; //將當前對象的引用暫時賦於temp,用於接收下一個對象的引用
}
}
}
//打印環形鏈表
public void showLink(){
Person t = firstPerson;
do{
System.out.println(t.no);
t = t.nextPerson; /*前一個對象的nextPerson存放的下一個對象的引用
(因爲對象也是引用類型,相當於是引用的引用)*/
}while(t!=firstPerson);
}
public void play(){
Person temp = this.firstPerson; //將第一個人這個對象的引用交給temp臨時變量
//找到開始數數的人
for(int i=1; i<k; i++){ // i<k是爲第k個人這個對象的引用保存在前k前一個人這個對象.nextPerson中
temp = temp.nextPerson; //假設k=2時,循環只執行一次,是將第二個人這個對象的引用交給temp
}
//數m下,找到出列的人 以下注釋只符合上面k=2的情況
while(this.len!=1){
for(int i=1; i<m; i++){
//找到出列的對象
temp = temp.nextPerson; /* 這裏假設m=3,第一次循temp = 第二個對象的.nextPerson(也就是第三個對象的引用)
第二次循環時temp = 第三個對象的.nextPerson(也就是第四個對象的引用)
從k=2人個開始數,數m=3下,第四個人就是出列的對象,邏輯結論正確!*/
}
System.out.println("第"+temp.no+"個人出列了!");
//找到要出列前一個人(對象) 續:可以在數到m-1時那個對象標記一下,可以不
Person temp2 = temp;
while(temp2.nextPerson!=temp){
temp2 = temp2.nextPerson;
}
//將數到m的人退出圈,即退出環鏈
temp2.nextPerson = temp.nextPerson; //將出列前一個對象的nextPerson交給出列對象的下一個對象
//讓temp指向下一個數數的人
temp = temp.nextPerson;
this.len--;
}
System.out.println("最後留下的人是:"+temp.no);
}
}
public class CycleLinkTest{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
System.out.print("請輸入圓桌數數遊戲的總人數:");
CycleLink t = new CycleLink();
t.setLen(input.nextInt()); //給定環形鏈表的長度(等同遊戲人數)
t.createLink(); //創建環鏈
// t.showLink(); //測試環鏈是否創建成功
System.out.print("從第幾個人開始數:");
t.setK(input.nextInt());
System.out.print("每次數幾下:");
t.setM(input.nextInt());
t.play();
}
}
/*********************
請輸入圓桌數數遊戲的總人數:7
從第幾個人開始數:2
每次數幾下:3
第4個人出列了!
第7個人出列了!
第3個人出列了!
第1個人出列了!
第6個人出列了!
第2個人出列了!
最後留下的人是:5
*********************/