约瑟夫环问题
一、问题描述
N个人围城一桌(首位相连),约定从1报数,报到数为k的人出局,然后下一位又从1开始报,以此类推。最后留下的人获胜。(有很多类似问题,如猴子选代王等等,解法都一样)
二、思路分析
(1)可将人的顺序简单编号,从1到N;
(2)构造一个循环链表,可以解决首位相连的问题,同时如果将人的编号改为人名或者其他比较方便
(3)将人的编号插入到结构体的Data域;
(4)遍历人的编号,输出参与的人的编号;
(5)开始报数,从头报数,报到k的人出局(删除次结点),(输出出局的人更人性化)避免浪费,可释放次结点。直到人数只有一个人时,退出循环。输出获胜的人。
(6)注意:在写删除删除结点的函数时都是针对K>=2的情况处理,所以要考虑k=1的情况,要是出局的密码为1时则最后一个获胜。
三、算法实现
(1)构造结构体
typedef struct Node{
int Num;//Data域
struct Node *next;
}JoseNode, *PNode, *HNode;//PNode为指针变量,HNode为头结点
(2)得到头结点
HNode h = ((HNode)malloc(sizeof(JoseNode)));
(3)初始化循环单链表
int JoseInit(HNode *h)
{
if (!h)
{
printf("初始化链表错误!\n");
return 0;
}
(*h)->next = (*h);//循环单链表
return 1;
}
(4)插入算法
int JoseInsert(JoseNode *h, int pos, int x)
{
PNode p=h,q;
int i=1;
if (pos == 1)/*尾插法*/
{
p->Num = x;
p->next = p;
return 1;
}
while(i<pos-1)
{
p=p->next;
i++;
}
q=(PNode)malloc(sizeof(JoseNode));
q->Num=x;
q->next=p->next;
p->next=q;
return 1;
}
for (i = 1; i <=N; i++)
{
JoseInsert(h, i, i);
}
(4)遍历算法
void TraverseList(HNode h, int M)
{
int i = 0;
PNode p = h;
printf("参与的人的编号为:\n");
while (i<M)
{
printf("%d\t", p->Num);
p = p->next;
i++;
}
printf("\n");
}
(5)找到出局的人,并删除(删除算法)
if(k > 1)//考虑出局密码为1时的情况
JoseDelete(h, N, k);
else
{
for(i = 1; i < N; i++)
printf("出局的人为:%d号\n",i);
printf("***************获胜者为:%d号***************",N);
}
int JoseDelete(HNode h, int M, int k)
{ int i;
PNode p=h,q;
while(M>1)//循环终止条件,只剩一个人时
{
for(i=1;i<k-1;i++)//此处为i<k-1,因为要找到的是出局的人的前一个结点①
{
p=p->next;
}
q=p->next;
p->next=q->next;
printf("出局的人为:%d号\n",q->Num);
free(q);//释放次结点
p=p->next;//与①处的相对应,①处找到的只是出局的人的前一个结点
M--;
}
printf("***************获胜者为:%d号***************",p->Num);
return 1;
}
四、完整代码
1 #include <stdio.h>
2 #include <malloc.h>
3
4 /*构建结构体*/
5 typedef struct Node{
6 int Num;
7 struct Node *next;
8 }JoseNode, *PNode, *HNode;
9
10 /**********初始化循环单链表*********/
11 int JoseInit(HNode *h)
12 {
13 if (!h)
14 {
15 printf("初始化链表错误!\n");
16 return 0;
17 }
18 (*h)->next = (*h);//循环单链表
19 return 1;
20
21 }
22
23 /*************单链表插入操作**********/
24 int JoseInsert(JoseNode *h, int pos, int x)
25 {
26 PNode p=h,q;
27 int i=1;
28 if (pos == 1)/*尾插法*/
29 {
30 p->Num = x;
31 p->next = p;
32 return 1;
33 }
34 while(i<pos-1)
35 {
36 p=p->next;
37 i++;
38 }
39 q=(PNode)malloc(sizeof(JoseNode));
40 q->Num=x;
41 q->next=p->next;
42 p->next=q;
43 return 1;
44 }
45
46 /*遍历*/
47 void TraverseList(HNode h, int M)
48 {
49 int i = 0;
50 PNode p = h;
51 printf("参与的人的编号为:\n");
52 while (i<M)
53 {
54 printf("%d\t", p->Num);
55 p = p->next;
56 i++;
57 }
58 printf("\n");
59 }
60 /**************出局函数****************/
61
62 int JoseDelete(HNode h, int M, int k)
63 { int i;
64 PNode p=h,q;
65 while(M>1)
66 {
67 for(i=1;i<k-1;i++)
68 {
69 p=p->next;
70 }
71
72 q=p->next;
73 p->next=q->next;
74 printf("出局的人为:%d号\n",q->Num);
75 free(q);
76
77 p=p->next;
78 M--;
79 }
80 printf("***************获胜者为:%d号***************",p->Num);
81 return 1;
82 }
83
84
85 /***************************************/
86 int main()
87 {
88 int i;//计数器
89 int N;//参与的人数
90 int k;//报数密码
91 printf("请输入参与人数:");
92 scanf("%d",&N);
93 printf("请输入出局密码:");
94 scanf("%d",&k);
95
96 /**************得到头结点****************/
97 HNode h = ((HNode)malloc(sizeof(JoseNode)));
98
99 /***************初始化单链表************/
100 JoseInit(&h);
101
102 /******将编号插入到循环单链表中******/
103 for (i = 1; i <=N; i++)
104 {
105 JoseInsert(h, i, i);
106 }
107 /**************遍历单链表***************/
108 TraverseList(h,N);
109
110 /***************出局函数************/
111 if(k > 1)
112 JoseDelete(h, N, k);
113 else
114 {
115 for(i = 1; i < N; i++)
116 printf("出局的人为:%d号\n",i);
117 printf("***************获胜者为:%d号***************",N);
118 }
119
120 printf("\n");
121 printf("\n");
122 return 0;
123 }
五、实验验证


浙公网安备 33010602011771号