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語言手動實現,有助於你更好的理解這些數據結構.
  • 相关阅读:
    【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
    【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
    【Java EE 学习 35 上】【strus2】【类型转换器】【struts2和Servlet API解耦】【国际化问题】【资源文件乱码问题已经解决】
    【Java EE 学习 34】【struts2学习第一天】
    【JavaScript中的正则表达式】
    【Java EE 学习 33 下】【validate表单验证插件】
    【Java EE 学习 33 上】【JQuery样式操作】【JQuery中的Ajax操作】【JQuery中的XML操作】
    【Java EE 学习 32 下】【JQuery】【JQuey中的DOM操作】
    【Java EE 学习 32 上】【JQuery】【选择器】
    【Java EE 学习 31】【JavaScript基础增强】【Ajax基础】【Json基础】
  • 原文地址:https://www.cnblogs.com/ltozvxe/p/13667962.html
Copyright © 2011-2022 走看看