JAVA數據結構 - 單向環形鏈表與約瑟夫問題

約瑟夫問題(有時也稱爲約瑟夫斯置換,是一個出現在計算機科學和數學中的問題。在計算機編程的算法中,類似問題又稱爲約瑟夫環。又稱“丟手絹問題”.)

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());        }}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章