关键字: 链表 约瑟夫环
这几天为了准备笔试忙着复习C语言,决定把当时学C时的一些经典问题再温习一下,当时啊,学的稀里糊涂的,呵呵,现在回头来仔细写一写代码,就算是纪念当时的个性十足的赵老师了吧!
约瑟夫问题的:编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
解决思路还是很简单的,主要是要会熟练运用单循环链表的数据结构,通过单循环链表模拟围坐的一圈人,然后根据相应的密码进行报数,然后删除相应的链表节点。下面是C代码:
1. #include <stdio.h>
2. #include <stdlib.h>
3. #define MAX_NODE_NUM 100
4. #define TRUE 1U
5. #define FALSE 0U
6.
7. typedef struct NodeType
8. {
9. int id;
10. int cipher;
11. struct NodeType *next;
12. } NodeType;
13.
14. /* 创建单向循环链表 */
15. static void CreaList(NodeType **, const int);
16. /* 运行"约瑟夫环"问题 */
17. static void StatGame(NodeType **, int);
18. /* 打印循环链表 */
19. static void PrntList(const NodeType *);
20. /* 得到一个结点 */
21. static NodeType *GetNode(const int, const int);
22. /* 测试链表是否为空, 空为TRUE,非空为FALSE */
23. static unsigned EmptyList(const NodeType *);
24.
25. int main(void)
26. {
27. int n, m;
28. NodeType *pHead = NULL;
29. while (1)
30. {
31. printf("请输入人数n(最多%d个): ", MAX_NODE_NUM);
32. scanf("%d", &n);
33. printf("和初始密码m: ");
34. scanf("%d", &m);
35. if (n > MAX_NODE_NUM)
36. {
37. printf("人数太多,请重新输入!\n");
38. continue;
39. }
40. else
41. break;
42. }
43. CreaList(&pHead, n);
44. printf("\n------------ 循环链表原始打印 -------------\n");
45. PrntList(pHead);
46. printf("\n-------------删除出队情况打印 -------------\n");
47. StatGame(&pHead, m);
48. }
49.
50. static void CreaList(NodeType **ppHead, const int n)
51. {
52. int i, iCipher;
53. NodeType *pNew, *pCur;
54. for (i = 1; i <= n; i++)
55. {
56. printf("输入第%d个人的密码: ", i);
57. scanf("%d", &iCipher);
58. pNew = GetNode(i, iCipher);
59. if (*ppHead == NULL)
60. {
61. *ppHead = pCur = pNew;
62. pCur->next = *ppHead;
63. }
64. else
65. {
66. pNew->next = pCur->next;
67. pCur->next = pNew;
68. pCur = pNew;
69. }
70. }
71. printf("完成单向循环链表的创建!\n");
72. }
73.
74. static void StatGame(NodeType **ppHead, int iCipher)
75. {
76. int iCounter, iFlag = 1;
77. NodeType *pPrv, *pCur, *pDel;
78. pPrv = pCur = *ppHead;
79. /* 将pPrv初始为指向尾结点,为删除作好准备 */
80. while (pPrv->next != *ppHead)
81. pPrv = pPrv->next;
82. while (iFlag)
83. {
84. for (iCounter = 1; iCounter < iCipher; iCounter++)
85. {
86. pPrv = pCur;
87. pCur = pCur->next;
88. }
89. if (pPrv == pCur)
90. iFlag = 0;
91. pDel = pCur; /* 删除pCur指向的结点,即有人出列 */
92. pPrv->next = pCur->next;
93. pCur = pCur->next;
94. iCipher = pDel->cipher;
95. printf("第%d个人出列, 密码: %d\n", pDel->id, pDel->cipher);
96. free(pDel);
97. }
98. *ppHead = NULL;
99. getchar();
100. }
101.
102. static void PrntList(const NodeType *pHead)
103. {
104. const NodeType *pCur = pHead;
105. if (EmptyList(pHead))
106. return;
107. do
108. {
109. printf("第%d个人, 密码: %d\n", pCur->id, pCur->cipher);
110. pCur = pCur->next;
111. } while (pCur != pHead);
112. getchar();
113. }
114.
115. static NodeType *GetNode(const int iId, const int iCipher)
116. {
117. NodeType *pNew;
118. pNew = (NodeType *)malloc(sizeof(NodeType));
119. if(!pNew)
120. {
121. printf("Error, the memory is not enough!\n");
122. exit(-1);
123. }
124. pNew->id = iId;
125. pNew->cipher = iCipher;
126. pNew->next = NULL;
127. return pNew;
128. }
129.
130. static unsigned EmptyList(const NodeType *pHead)
131. {
132. if(!pHead)
133. {
134. printf("The list is empty!\n");
135. return TRUE;
136. }
137. return FALSE;
138. }