约瑟夫环问题

来源:互联网 发布:做网络直播赚钱吗 编辑:程序博客网 时间:2024/06/06 02:10

      约瑟夫问题:设有n个人围坐在圆桌周围,现在从某个位置m(1<=m<n)上的人开始报数,数报到k的人就站出来。下一个人,即原来的第k+1个位置的人,又从1开始报数,再报数到k的人站出来。一次重复下去,指导全部的人站出来为止。试设计一个程序求出这个出列序列。
     代码如下:

Code:
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #define bool int   
  4. #define true 0   
  5. #define false 1   
  6. struct link_node {   
  7.     int pos;   
  8.     struct link_node *next;   
  9. };   
  10.   
  11. struct link_node *create_list(int n)   
  12. {   
  13.     int i;   
  14.     struct link_node  *new_node = NULL, *head =NULL, *tail = NULL;   
  15.     for (i = 1;i <= n; i++) {   
  16.         new_node = (struct link_node *)malloc(sizeof(struct link_node));   
  17.         if (new_node == NULL)   
  18.             return NULL;   
  19.         new_node->pos = i;   
  20.         if (i == 1) {   
  21.             head = new_node;   
  22.             tail = new_node;   
  23.             new_node->next = NULL;   
  24.         } else {   
  25.             new_node->next = tail->next;   
  26.             tail->next = new_node;   
  27.             tail = new_node;   
  28.         }   
  29.     }   
  30.     tail->next = head;   
  31.     return head;   
  32. }   
  33.   
  34. bool josephus(struct link_node *plist, int n, int m, int k)   
  35. {   
  36.     if (m > n || plist == NULL)   
  37.         return false;   
  38.        
  39.     int i;   
  40.     struct link_node *p = NULL, *q = NULL;   
  41.     for (i = 1; i < m; i++)   
  42.         plist = plist->next;   
  43.     while (plist != NULL) {   
  44.         if (plist->next == plist) {/*if *plist is the last node, print and free p*/  
  45.             printf("%d ", plist->pos);   
  46.             free(plist);  
  47.             plist = NULL;  
  48.         } else {/*find the kth node*/  
  49.             if (k % n == 1) {/*if the kth node is the plist ltself, find the front node, free plist*/  
  50.                 p = plist;   
  51.                 do {   
  52.                     p = p->next;   
  53.                 } while (p->next != plist);   
  54.                 p->next = plist->next;   
  55.                 q = plist;   
  56.                 plist = plist->next;   
  57.                 printf("%d ", p->pos);   
  58.                 free(q);   
  59.             } else {   
  60.                 int count;   
  61.                 if (k % n == 0)   
  62.                     count = n - 1;   
  63.                 else  
  64.                     count = k % n - 1;   
  65.                 for (i = 1; i < count; i++) {   
  66.                     plist = plist->next;   
  67.                 }              
  68.                 p = plist->next;   
  69.                 plist->next = p->next;   
  70.                 printf("%d ", p->pos);   
  71.                 free(p);   
  72.                 plist = plist->next;   
  73.             }   
  74.         }   
  75.     }   
  76.     return true;   
  77. }   
  78. int main()   
  79. {   
  80.     int n, m, k;   
  81.     struct link_node *list = NULL;   
  82.     scanf("%d, %d, %d", &n, &m, &k);   
  83.     list = create_list(n);   
  84.     josephus(list, n, m, k);   
  85.     return 0;   
  86. }  

      看别人在网上写的这个解题的程序,相对而言程序比我的简单,这里程序考虑的地方有:
      1.由于要创建的是无头结点的循环单链表,初始化的时候,头结点是为空的,如果把20-23代码放在循环外面,循环次数少一即可,这样程序的循环流水线不被打断,效率应该高些,可我固执的以为创建的过程要在一起。
      2.题目要求的是输出出序序列。假设有3个人,报数要报到10的人出列的话,那多循环就转了很多圈了.所以这里采用k%n的方式,并根据情况分别处理。
      这里说一下,我刚写出来的时候在46,47行犯了个毛病,最开始的版本是先设置指针值为空然后才释放,为这个问题我找了好久,最后才找到了原因。

      最后约瑟夫环问题网上还有高效的数学解法,以后再看看。