**有n个人围成一圈,顺序排号,从第一个开始报数(从1到3报数),凡报到3的人退出圈子,问最后最后留下的是原来第几号的那位. **
约瑟夫问题
基于环形链表实现
这里要注意的是
代码中的变量k用来记录现在报的数
当k为2时,则说明下一个人报数3,释放下一个人的空间(把下一个人踢出队列),若等到k为3再释放,还要记录上一个人的next的指向,指向k为3的next,所以在k=2时就处理,会比较方便
编号从一开始
输入总人数
输出最后留下的那个人的编号
具体解释已在代码注释中给出,若有不懂,可以评论区留言或者私信,我会尽快回复的。
#include <stdio.h>
#include <stdlib.h>
typedef struct node //定义链表
{
int number; //存储每个人的编号,从1开始
struct node* next;
}Link,*PLink;
int yue(int n); //判断约瑟夫问题最后的答案
int main()
{
int n;
printf("请输入人数:");
scanf("%d", &n);
printf("最后留下的人是:%d\n", yue(n));
return 0;
}
int yue(int n)
{
PLink head = NULL; //头指针
PLink p = NULL, q = NULL; //建链表辅助指针
for (int i = 0; i < n; i++)
{
q = (PLink)malloc(sizeof(Link)); //申请新的空间
q->number = i + 1;
q->next = NULL;
if (head == NULL)
head = q; //头指针为空,则给头指针指向申请的空间
else
p->next = q;
p = q; //保留此次循环申请的空间
}
p->next = head; //结尾next指向头部,组成环形链表
int k = 0;
//int j = 7;
while (1)
{
if (head->next == head) //当环形链表只剩一个元素时,结束循环
break;
k++;
if (k == 2) //当k为2时,则说明下一个人报数3,释放下一个人的空间,若等到k为3再释放,情况会较麻烦
{
printf("%d\n", head->next->number); //打印出出列的人
q = head->next;
head->next = head->next->next; //next直接指向下下个元素
free(q); //释放下一个元素
k = 0;
}
head = head->next;
}
return head->number; //返回最后剩下的那个人的编号
}
运行截图: