約瑟夫環(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 }