约瑟夫问题:设有n个人围坐在圆桌周围,现在从某个位置m(1<=m<n)上的人开始报数,数报到k的人就站出来。下一个人,即原来的第k+1个位置的人,又从1开始报数,再报数到k的人站出来。一次重复下去,指导全部的人站出来为止。试设计一个程序求出这个出列序列。
代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #define bool int
- #define true 0
- #define false 1
- struct link_node {
- int pos;
- struct link_node *next;
- };
- struct link_node *create_list(int n)
- {
- int i;
- struct link_node *new_node = NULL, *head =NULL, *tail = NULL;
- for (i = 1;i <= n; i++) {
- new_node = (struct link_node *)malloc(sizeof(struct link_node));
- if (new_node == NULL)
- return NULL;
- new_node->pos = i;
- if (i == 1) {
- head = new_node;
- tail = new_node;
- new_node->next = NULL;
- } else {
- new_node->next = tail->next;
- tail->next = new_node;
- tail = new_node;
- }
- }
- tail->next = head;
- return head;
- }
- bool josephus(struct link_node *plist, int n, int m, int k)
- {
- if (m > n || plist == NULL)
- return false;
- int i;
- struct link_node *p = NULL, *q = NULL;
- for (i = 1; i < m; i++)
- plist = plist->next;
- while (plist != NULL) {
- if (plist->next == plist) {/*if *plist is the last node, print and free p*/
- printf("%d ", plist->pos);
- free(plist);
- plist = NULL;
- } else {/*find the kth node*/
- if (k % n == 1) {/*if the kth node is the plist ltself, find the front node, free plist*/
- p = plist;
- do {
- p = p->next;
- } while (p->next != plist);
- p->next = plist->next;
- q = plist;
- plist = plist->next;
- printf("%d ", p->pos);
- free(q);
- } else {
- int count;
- if (k % n == 0)
- count = n - 1;
- else
- count = k % n - 1;
- for (i = 1; i < count; i++) {
- plist = plist->next;
- }
- p = plist->next;
- plist->next = p->next;
- printf("%d ", p->pos);
- free(p);
- plist = plist->next;
- }
- }
- }
- return true;
- }
- int main()
- {
- int n, m, k;
- struct link_node *list = NULL;
- scanf("%d, %d, %d", &n, &m, &k);
- list = create_list(n);
- josephus(list, n, m, k);
- return 0;
- }
看别人在网上写的这个解题的程序,相对而言程序比我的简单,这里程序考虑的地方有:
1.由于要创建的是无头结点的循环单链表,初始化的时候,头结点是为空的,如果把20-23代码放在循环外面,循环次数少一即可,这样程序的循环流水线不被打断,效率应该高些,可我固执的以为创建的过程要在一起。
2.题目要求的是输出出序序列。假设有3个人,报数要报到10的人出列的话,那多循环就转了很多圈了.所以这里采用k%n的方式,并根据情况分别处理。
这里说一下,我刚写出来的时候在46,47行犯了个毛病,最开始的版本是先设置指针值为空然后才释放,为这个问题我找了好久,最后才找到了原因。
最后约瑟夫环问题网上还有高效的数学解法,以后再看看。