约瑟夫环(Josephus)由来:
约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提处的,他参加并记录了公园66-70年犹太人反抗罗马的起义。约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷后,他和40名顽强的将士在附近的一个山洞避难。在那里,这些叛乱者表决说“要投降毋宁死”。于是,决定了一个自杀方式。他们41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。约瑟夫有预谋地将朋友和自己安排在第16个和第31个位置,逃过了这场死亡游戏,并一起投降了罗马。
约瑟夫问题具体描述是:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个。例如N=5,M=3,被杀掉的顺序是:3,1,5,2,4。
实验结果如图:
约瑟夫问题:
实验完整代码如下:
1 #include <stdio.h>
2 #include <malloc.h>
3 /*常量定义*/
4 #define OK 0
5 #define Err_Memory -1
6 #define Err_InvalidParam -2
7 typedef int Status;
8
9 /*节点结构定义*/
10 typedef int ElemType;
11 typedef struct node{
12 ElemType id;
13 struct node *next;
14 } *LinkList, ListNode;
15
16 Status CreateList(LinkList Head, int n)
17 {
18 ListNode *p, *s;
19 int i;
20
21 if (!Head)
22 return Err_InvalidParam;
23
24 Head->next = Head;
25 p = Head;
26
27 for(i = 1; i<=n; i++){
28 s = (ListNode *)malloc(sizeof(ListNode));
29 s->id = i;
30 s->next = p->next;
31 p->next = s;
32 p = p->next;
33 printf("第%d个序号为:%d\n", i, p->id);
34 }
35
36 return OK;
37 }
38
39 int Josephus(LinkList Head, int m)
40 {
41 int iCount = 1, iOrder = 0;
42 ListNode *pcur, *pprev, *pdel;
43
44 if (!Head)
45 return Err_InvalidParam;
46
47 pprev = Head;
48 pcur = Head->next;
49 while(pprev != pcur->next){
50 if (pcur != Head && iCount == m){
51 pdel = pcur;
52 pprev->next = pcur->next;
53 pcur = pcur->next;
54 iOrder++;
55 printf("第%d个出列序号为:%d\n", iOrder, pdel->id);
56 free(pdel);
57 iCount = 1;
58 } else {
59 if (pcur != Head)
60 iCount ++;
61 pprev = pcur;
62 pcur = pcur->next;
63 }
64 }
65
66 printf("第%d个出列序号为:%d\n", ++iOrder, pcur->id);
67 free(pcur);
68 free(pprev);
69
70 return OK;
71 }
72
73 void main()
74 {
75 int n, m;
76 LinkList Joseph;
77 printf("请输入参与人数n:\n");
78 scanf("%d", &n);
79 printf("请输入报数上限m:\n");
80 scanf("%d", &m);
81 Joseph = (ListNode *)malloc(sizeof(ListNode));
82 if (CreateList(Joseph, n) != OK){
83 printf("链表创建错误\n");
84 return;
85 }
86 if(Joseph->next == Joseph){
87 printf("参与人数输入错误\n");
88 return;
89 }
90 printf("\n");
91 Josephus(Joseph, m);
92
93 }