Josephu问题:编号为0到N-1的N个人围成一圈,然后从1开始报数,报到M的那个人被杀掉,剩下的人接着从1开始报数,求最后的幸存者编号。
前面给出了该问题的数学解法,下面贴上链表方法,直接模拟整个过程。
#include <stdio.h>
#include <stdlib.h>
struct node {
int num;
struct node *next;
};
typedef struct node *node_t;
node_t create_circular_list(int n);
int josephu(int n, int m);
int main(int argc, char **argv)
{
int N, M;
printf("input N and M:");
scanf("%d%d", &N, &M);
printf("result: %d\n", josephu(N, M));
return 0;
}
node_t create_circular_list(int n)
{
if (n <= 0)
return NULL;
node_t head, tmp;
head = (node_t)malloc(sizeof(*head));
if (NULL == head) {
printf("malloc erro, line: %d\n", __LINE__);
return NULL;
}
head->num = 0;
head->next = head;
int i;
tmp = head;
for (i = 1; i < n; i ++) {
tmp = (tmp->next = (node_t)malloc(sizeof(*tmp)));
if (NULL == tmp) {
printf("malloc erro, line: %d\n", __LINE__);
return NULL;
}
tmp->num = i;
tmp->next = head;
}
return head;
}
int josephu(int n, int m)
{
node_t head = create_circular_list(n);
if (NULL == head) {
printf("create list erro\n");
return -1;
}
node_t *curr = &head;//此处仅仅是为了练习二级指针在单向链表中的删除操作,可以换别的简单易懂的方法实现
while (--n) {
node_t entry = *curr;
int i;
for (i = 1; i < m; i ++) {
curr = &entry->next;
entry = entry->next;
}
*curr = entry->next;//kill
free(entry);
}
int ret = (*curr)->num;
free(*curr);
return ret;
}