约瑟夫环问题

一、问题描述

N个人围城一桌(首位相连),约定从1报数,报到数为k的人出局,然后下一位又从1开始报,以此类推。最后留下的人获胜。(有很多类似问题,如猴子选代王等等,解法都一样)

二、思路分析

    (1)可将人的顺序简单编号,从1到N;

    (2)构造一个循环链表,可以解决首位相连的问题,同时如果将人的编号改为人名或者其他比较方便

         (3)将人的编号插入到结构体的Data域;

         (4)遍历人的编号,输出参与的人的编号;

         (5)开始报数,从头报数,报到k的人出局(删除次结点),(输出出局的人更人性化)避免浪费,可释放次结点。直到人数只有一个人时,退出循环。输出获胜的人。

   (6)注意:在写删除删除结点的函数时都是针对K>=2的情况处理,所以要考虑k=1的情况,要是出局的密码为1时则最后一个获胜。

三、算法实现

      (1)构造结构体

                  typedef struct Node{

                                   int Num;//Data域

                                   struct Node *next;

      }JoseNode, *PNode, *HNode;//PNode为指针变量,HNode为头结点

       (2)得到头结点

                HNode h = ((HNode)malloc(sizeof(JoseNode)));

  (3)初始化循环单链表

             int JoseInit(HNode *h)

    {

                            if (!h)

                            {

                            printf("初始化链表错误!\n");

                            return 0;

                            }

                            (*h)->next = (*h);//循环单链表

                            return 1;

 

    }

(4)插入算法

            int JoseInsert(JoseNode *h, int pos, int x)

{      

                          PNode p=h,q;

                          int i=1;

                           if (pos == 1)/*尾插法*/

                           {

                          p->Num = x;

                          p->next = p;

                          return 1;

                          }

                          while(i<pos-1)

                          {

                          p=p->next;

                          i++;

                          }

                          q=(PNode)malloc(sizeof(JoseNode));

                          q->Num=x;

                          q->next=p->next;

                          p->next=q;

                          return 1;

}

 

 

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

                  {

                          JoseInsert(h, i, i);

                  }

(4)遍历算法

void TraverseList(HNode h, int M)

{

                          int i = 0;

                          PNode p = h;

                           printf("参与的人的编号为:\n");

                          while (i<M)

                          {

                          printf("%d\t", p->Num);

                          p = p->next;

                          i++;

                  }

                  printf("\n");

}

 

(5)找到出局的人,并删除(删除算法)

  if(k > 1)//考虑出局密码为1时的情况

              JoseDelete(h, N, k);

       else

       {

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

                     printf("出局的人为:%d号\n",i);

              printf("***************获胜者为:%d号***************",N);

       }

 

 

      int JoseDelete(HNode h, int M, int k)

{       int i;

                  PNode p=h,q;

                  while(M>1)//循环终止条件,只剩一个人时

                  {

                          for(i=1;i<k-1;i++)//此处为i<k-1,因为要找到的是出局的人的前一个结点①

                          {

                                   p=p->next;

                          }

                 

                          q=p->next;

                          p->next=q->next;

                           printf("出局的人为:%d号\n",q->Num);

                          free(q);//释放次结点

 

                          p=p->next;//与①处的相对应,①处找到的只是出局的人的前一个结点

                          M--;

                  }

         printf("***************获胜者为:%d号***************",p->Num);

         return 1;

}

 

 

四、完整代码

  

复制代码
  1 #include <stdio.h>
  2 #include <malloc.h>
  3 
  4 /*构建结构体*/
  5 typedef struct Node{
  6     int Num;
  7     struct Node *next;
  8 }JoseNode, *PNode, *HNode;
  9 
 10 /**********初始化循环单链表*********/
 11 int JoseInit(HNode *h)
 12 {
 13     if (!h)
 14     {
 15         printf("初始化链表错误!\n");
 16         return 0;
 17     }
 18     (*h)->next = (*h);//循环单链表
 19     return 1;
 20 
 21 }
 22 
 23 /*************单链表插入操作**********/
 24 int JoseInsert(JoseNode *h, int pos, int x)
 25 {    
 26     PNode p=h,q;
 27     int i=1;
 28     if (pos == 1)/*尾插法*/
 29     {
 30         p->Num = x;
 31         p->next = p;
 32         return 1;
 33     }
 34     while(i<pos-1)
 35     {
 36         p=p->next;
 37         i++;
 38     }
 39     q=(PNode)malloc(sizeof(JoseNode));
 40     q->Num=x;
 41     q->next=p->next;
 42     p->next=q;
 43     return 1;
 44 }
 45 
 46 /*遍历*/
 47 void TraverseList(HNode h, int M)
 48 {
 49     int i = 0;
 50     PNode p = h;
 51     printf("参与的人的编号为:\n");
 52     while (i<M)
 53     {
 54         printf("%d\t", p->Num);
 55         p = p->next;
 56         i++;
 57     }
 58     printf("\n");
 59 }
 60 /**************出局函数****************/
 61 
 62 int JoseDelete(HNode h, int M, int k)
 63 {    int i;
 64     PNode p=h,q;
 65     while(M>1)
 66     {
 67         for(i=1;i<k-1;i++)
 68         {
 69             p=p->next;
 70         }
 71         
 72         q=p->next;
 73         p->next=q->next;
 74         printf("出局的人为:%d号\n",q->Num);
 75         free(q);
 76 
 77         p=p->next;
 78         M--;
 79     }
 80     printf("***************获胜者为:%d号***************",p->Num);
 81     return 1;
 82 }
 83 
 84 
 85 /***************************************/
 86 int main()
 87 {
 88     int i;//计数器
 89     int N;//参与的人数
 90     int k;//报数密码
 91     printf("请输入参与人数:");
 92     scanf("%d",&N);
 93     printf("请输入出局密码:");
 94     scanf("%d",&k);
 95 
 96 /**************得到头结点****************/
 97     HNode h = ((HNode)malloc(sizeof(JoseNode)));
 98 
 99 /***************初始化单链表************/
100     JoseInit(&h);
101 
102 /******将编号插入到循环单链表中******/
103     for (i = 1; i <=N; i++)
104     {
105         JoseInsert(h, i, i);
106     }
107 /**************遍历单链表***************/
108     TraverseList(h,N);
109 
110 /***************出局函数************/
111     if(k > 1)
112     JoseDelete(h, N, k);
113     else
114     {
115         for(i = 1; i < N; i++)
116             printf("出局的人为:%d号\n",i);
117         printf("***************获胜者为:%d号***************",N);
118     }
119 
120     printf("\n");
121     printf("\n");
122     return 0;
123 }
复制代码

 


五、实验验证

  

posted on 2017-11-13 22:23  3r3r3www  阅读(207)  评论(0编辑  收藏  举报

导航