zoukankan      html  css  js  c++  java
  • C語言之約瑟夫問題--鏈錶的創建和元素刪除.

    故事:

    約瑟夫在自己的日記中寫道,他和他的40個戰友被羅馬軍隊包圍在洞中。他們討論是自殺還是被俘,最終決定自殺,並以抽籤的方式決定誰殺掉誰。約瑟夫斯和另外一個人是最後兩個留下的人。約瑟夫說服了那個人,他們將向羅馬軍隊投降,不再自殺。約瑟夫把他的存活歸因於運氣或天意,他不知道是哪一個.

    這個問題也被稱作約瑟夫問題,或者約瑟夫環,圓桌遊戲等.將其抽象之後形成下面的遊戲規則:

    1. 有一群人圍坐成一圈.
    2. 從第一個人開始報數.
    3. 每次報道3該人自殺.
    4. 下一人衝1開始報數.

    使用C語言實現:

    #include<stdio.h>
    #include<stdlib.h>
    
    // 定義玩家(定義鏈錶節點)
    typedef struct _
    {
        int no;                 // 記錄玩家的編號(數據域)
        struct _ *next;         // 指向下一個玩家的指針(指針域)
    } Player;
    
    // 生成玩家(生成鏈錶)
    Player *CreatePlayers(int number)
    {
        Player *head;       // 第一位玩家(鏈錶頭節點)
        Player *tail;       // 最後一位玩家(鏈錶尾結點)
        Player *temp;       // 用於申請空間的臨時變量
        head = (Player *)malloc(sizeof(Player));
    
        // 判斷空間是否申請成功
        if(NULL == head || NULL == tail)
        {
            printf("malloc fail!
    ");
            return NULL;
        }
    
        head->next = NULL;      // 還沒有後續結點,所以下一個結點為空
        head->no = 1;           // 把頭結點設置為第一個結點,後面不用判斷和
        tail = head;            // 讓頭結點和尾結點指向相同的節點
    
        // 生成遊戲玩家(生成鏈錶,並初始化數據域)
        int i;
        for(i = 2; i <= number; i++)
        {      
            temp = (Player *)malloc(sizeof(Player));        // 生成的新玩家(將要加入的新節點)
    
            // 判斷空間是否申請成功
            if(NULL == temp)
            {
                printf("malloc fail!
    ");
                return 0;
            }
    
            temp->no = i;           // 數據域初始化
            temp->next = NULL;      // 由於使用的是尾插法,所以新節點的指針指向空,如果是頭插法則指向頭結點
            tail->next = temp;      // 讓玩家加入玩家列表(將節點添加到鏈錶末尾)
            tail = temp;            // 新加入節點之後原來的尾結點已經不是最後一個節點
        }
        tail->next = head;          // 尾結點指向頭結點,形成閉環,如果是單鏈表,不用成環則沒有這條語句
        return head;                // 返回頭結點
    }
    
    // 查看所有玩家(遍歷鏈錶,確保自己生成成功)
    void ShowAllPlayer(Player *head)
    {
        Player *t = head;
        do
        {
            // 因為t指正是從head節點出發,最終回到head節點,使用do/while語句比while更簡潔
            printf("Player No: %d Is Coming!!!
    ",t->no);
            t = t->next;
        } while (t != head); 
    }
    
    // 遊戲開始
    void GameStart(Player *head)
    {
        // 讓兩個指針同時指向鏈錶的頭
        Player *temp1 = head;
        Player *temp2 = head;
    
        int number = 1;         // 玩家總人數(鏈錶節點數量)
        int setpSzie = 3;              // 控制單次循環步長
    
        while(temp2->next != temp1)
        {
            // 通過遍歷的方式讓temp2成為temp1的上一個節點,同時獲取總的節點數量
            temp2 = temp2->next;
            number++;
        }
    
        // 遊戲開始,每一次外層循環就會死一個人(每次循環減少一個節點)
        for(number; number > 0; number--)
        {
            // 找出本輪遊戲的出局者
            for(setpSzie = 3;setpSzie > 1; setpSzie--)
            {
                temp1 = temp1->next;
                temp2 = temp2->next;
            }
    
            temp2->next = temp1->next;                          // 讓temp1的上一個節點指向自己的下一個節點,保證自己的內存被釋放只後鏈錶不會斷裂
            printf("Player No: %d game over
    ",temp1->no);      // 玩家淘汰
            free(temp1);                                        // 釋放被淘汰的玩家的節點空間
            temp1 = temp2->next;                                // 指定下一輪遊戲的開始者
        }
        
    }
    
    int main(int argc, char const *argv[])
    {
        Player *head = CreatePlayers(10);
        ShowAllPlayer(head);
        printf("--------------------------
    ");
        GameStart(head);
        return 0;
    }

    執行結果:

      

    注意事項:

    1. 使用尾插法創建鏈錶的時候,需要先將節點加入鏈錶,然後再講尾結點的標誌後移,如果先將尾結點移動到新節點會導致原本的尾結點沒有標記
    2. 每次創建新的節點的時候需要將其指針指向null.
    3. 在刪除鏈錶元素的時候要先將當前的前驅節點指向後繼節點,確保節點刪除之後鏈錶不會讓鏈錶斷裂,在添加元素的時候則是讓新節點的指針指向後繼節點,然後讓前驅節點指向需要插入的節點,比較簡單,不做代碼展示.
    4. 如果只需要生成單鏈表,那麼只需要在生成的最後不要讓尾結點指向頭結點即可
    5. 鏈錶的頭結點既可以作為鏈錶的標誌,不存放實際數據存在,也可以存放數據,作為有效節點處理,具體而言看個人喜好.
    6. 雙向鏈錶只需要在指針域使用雙指針,一個指向後繼節點,一個指向前驅節點即可.
    7. 鏈錶的數據域可以存放多個數據,主要在於你結構體如何定義.
    8. 如果是C++等其他語言基本都會有已經封裝好的庫(如STL),雖然可以直接調用,但是使用C語言手動實現,有助於你更好的理解這些數據結構.
  • 相关阅读:
    linux安装maven
    Jenkins 改成中文语言显示
    appium怎么按下系统按键?如按下返回键、home键等等
    Jenkins+TestNG+gitlab+maven持续集成
    问题一:使用AndroidDriver而非原来的AppiumDriver的原因
    appium教程
    问题二:appium 搞定权限弹框的一个小办法
    问题三:Appium 的 UIAutomator2 模式下使用 sendKeys 出现错误
    TestNG执行顺序控制
    idea Mac 快捷键
  • 原文地址:https://www.cnblogs.com/ltozvxe/p/13667962.html
Copyright © 2011-2022 走看看