约瑟夫环问题(C语言、数据结构版)
一、问题描述
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("初始化链表错误! ");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("参与的人的编号为: ");
while (i<M)
{
printf("%d ", p->Num);
p = p->next;
i++;
}
printf(" ");
}
(5)找到出局的人,并删除(删除算法)
if(k > 1)//考虑出局密码为1时的情况
JoseDelete(h, N, k);
else
{
for(i = 1; i < N; i++)
printf("出局的人为:%d号 ",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号 ",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("初始化链表错误! "); 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("参与的人的编号为: "); 52 while (i<M) 53 { 54 printf("%d ", p->Num); 55 p = p->next; 56 i++; 57 } 58 printf(" "); 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号 ",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号 ",i); 117 printf("***************获胜者为:%d号***************",N); 118 } 119 120 printf(" "); 121 printf(" "); 122 return 0; 123 }
五、实验验证
经过验证,实验成功!如果有不足的地方,请大家指出来,一起探讨!写得不清楚的可以与我联系。