用循環鏈表和C語言實現約瑟夫環


需求分析

一群小孩編號為1,2,…,n(n>0)圍成一圈,有一個剛出鍋的山芋在他們之間傳遞。假設剛開始由1號拿着山芋,然后依次計數把山芋交給下一個小孩,當數到某個特定的k時,拿着山芋的小孩退出游戲,然后從下一個小孩重新開始計數,如此不斷,最后剩下的那個孩子就是幸運者。要求設計一個程序模擬次過程,並給出不同的n,k組合下那個幸運者是誰?

1、    輸入的形式和輸入值的范圍:演示程序以用戶和計算機的對話方式執行,即在計算機終端上顯示“提示信息”之后,由用戶在鍵盤上輸入相應的數據,每個人的序號由程序自動分配。以int型輸入,范圍在-2147483648~2147483648;

2、    輸出的形式:int型;

3、    程序所能達到的功能:構造鏈表;輸入數據;執行報數;儲存出列人的序號,刪除出列人的信息以及把指向出列人的指針移到出列人的下一個人,然后重新開始執行報數;直到最后一個人報數完畢,程序結束。

4、    測試數據:n=9,9個人的序號分別為:1,2,3,4,5,6,7,8,9。然后b=1,從第一個開始報數。k=5,則確定輸出的序列為:5,1,7,4,3,6,9,2,8。

 

#include<stdio.h>

#include<stdlib.h>

//聲明循環鏈表結構體

typedef struct LNode

{

      int num;//數據域

      struct LNode *next;//結構體指針

}LNode;//結點類型

 

//創建結點

LNode *Create_node(int Lnum)

{

      LNode *Lp;//創建結點指針

      Lp=(LNode *)malloc(sizeof(LNode));//分配動態儲存空間

      Lp->num=Lnum;//*Lp指向num,把num的值傳給Lnum

      Lp->next=NULL;//*Lp指向下一個元素結點為空,確定*Lp是頭結點指針

      return Lp;//返回頭結點指針

}

 

//創建循環鏈表

LNode *Create_Linklist(LNode *pHead, int Lsum)

{

      int k;

      LNode *p, *temp;//創建兩個指針

      for(k=1;k<=Lsum;k++)//遍歷整個鏈表

      {

             p=Create_node(k);

             //如果鏈表為空,創建鏈表第一個結點,其next指針指向自身

             if(pHead==NULL)

             {

                    temp=p; //把p的值傳給temp

                    pHead=p; //把p的值傳給pHead

                    temp->next=pHead; //讓*temp指向的下一個位置為pHead

             }

             //否則,執行插入節點操作

             else

             {

                    p->next=temp->next;//空白指針跟着*p后面,一個接一個插入

                    temp->next=p;

                    temp=p; //把p的值再傳給temp

             }

      }

//測試是否生成循環鏈表成功!

 

      p=pHead;

      k=1;//初始化k的值

      while(p->next!=pHead)//用循環輸出鏈表中的元素

      {

             printf("第%d個小孩的編號為:%d\n",k,p->num);

             p=p->next;//指針移向下一個位置

             k++;

      }

      printf("第%d個小孩的編號為:%d\n\n",k,p->num);//確保最后一個元素能顯示出來

 

      return pHead;//返回頭指針

}

 

//執行出列操作

void Delete_Linklist(LNode *pHead,int Lstart, int Ldel)

{

      int i,count=1;//count為計數器

      LNode *p, *temp;

      p=pHead;

      //找到第M個孩子所在的位置

      for(i=1;i<Lstart;i++)

             p=p->next;

      //只剩1個結點時終止循環

      while(p->next!=p)

      {

             //找到要出列的孩子的位置

             for(i=1;i<Ldel;i++)

             {

                    temp=p;

                    p=p->next;

             }

             //執行出列操作

             temp->next=p->next;//讓*temp指向*p后面的結點

             printf("第%d個出列的小孩的編號為:%d\n",count,p->num);

             free(p);//釋放*p

             count++;

             //出列者的下一個孩子作為新的第一個報數者

             p=temp->next;

      }

      printf("第%d個出列的小孩的編號為:%d\n",count,p->num);

      free(p);

      //所有人均出列,頭結點釋放后賦空值,避免出現懸垂指針

      pHead=NULL;

}

 /*主函數*/

int main()

{

      int n,b,k;

      LNode *pHead=NULL, *p;//執行初始化操作

    //輸入字符的合法性驗證暫時忽略

      printf("請輸入小孩的個數:\n");

      scanf("%d",&n);

      printf("請輸入開始報數的小孩編號:\n");

      scanf("%d",&b);

      printf("請輸入報數數目:\n");

      scanf("%d",&k);

      p=Create_Linklist(pHead,n);//調用創建鏈表函數

      Delete_Linklist(p,b,k);//調用刪除鏈表函數

      return 0;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM