用循环链表解决约瑟夫问题

约瑟夫问题描述:
从N个人中选出一个领导人,方法如下:所有人排除一个圆圈,按顺序数数,每数到第M的人出局,此时他两边的人
靠拢重新形成圆圈,从已出局人的下一个继续进行。问题是找出哪一个人将会是最后剩下的那个人,甚至我们更希望
知道出局人的顺序。

算法思路:
构造一个循环链表来表示排成圆圈的人。每人的链接指向圆圈内他左边(或者右边)的人。圆圈内人第i个人用整数i
表示。首先为1号构造一个节点的循环链表,然后再把2~N号插入到1号节点之后,得到一个1~N的环,并时x指向节点N
。然后从1号开始,跳过M-1个节点,把第M-1个节点的链接指向M+1号节点,即将第M个出局。继续这个过程,直到剩下
一个节点为止。

实现代码:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct node* link;
 5 struct node {int item; link next;};
 6 
 7 int main(int argc, char *argv[])
 8 {
 9     int i, N=atoi(argv[1]), M=atoi(argv[2]);
10     link t = malloc(sizeof *t), x = t;
11     t->item = 1;
12     t->next = t;
13     for(i=2; i<=N; i++)
14     {
15         x->next = malloc(sizeof *x);
16         x = x->next;
17         x->item = i;
18         x->next = t;
19     }
20     
21     while(x != x->next)
22     {
23         for(i=1; i<M; i++) x = x->next;
24         t = x->next;
25         printf("%d
", t->item);
26         x->next = t->next;
27         free(t);
28     }
29     printf("The leader is:%d
", x->item);
30     
31     system("pause");
32     return 0;
33 }

此代码参考了《算法:C语言实现(第1~4部分)》的程序3.9(p52),并做了一些修改。

将代码在Dev C++中编译,并将参数设置为9 5(中间用空格隔开),即N为9,M为5,运行结果如下:

5
1
7
4
3
6
9
2
The leader is:8
请按任意键继续. . .

特别的,如果将参数设置为9 1(中间用空格隔开),即N为9,M为1, 结果很容易想到,其如下:

1
2
3
4
5
6
7
8
The leader is:9
请按任意键继续. . .

 

本文参考文献:《算法:C语言实现(第1~4部分)》,机械工业出版社,2011.8

原文地址:https://www.cnblogs.com/geekham/p/4104684.html