思路:
我们要创建两个指针
有一个指针pcur指向头结点,该pcur作为报数的指针,还有一个指针ptail指向尾结点,作为记录pcur的地址
每报数为m时,pcur指向下一个元素的地址,ptail销毁报数为m的地址,然后ptail指向pcur,继续重新报数
最后当只剩一个元素时,即pcur->next==pcur,退出循环
答案:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct ListNode {
int val;
struct ListNode* next;
}ListNode;
ListNode* buyNode(int x) //申请一个新结点
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
if (node == NULL) //如果开辟空间失败
{
perror("malloc fail!");
exit(1);
}
node->val = x;
node->next = NULL;
return node;
}
ListNode* creatCircle(int n) //创建循环链表
{
ListNode* phead = buyNode(1); //创建第一个结点
ListNode* ptail = phead;
for (int i = 2; i <= n; i++) //创建n-1个结点
{
ptail->next = buyNode(i);
ptail = ptail->next;
}
ptail->next = phead; //首尾相连
return ptail;
}
void ysf(int n, int m) //约瑟夫函数
{
ListNode* prev = creatCircle(n); //尾结点
ListNode* pcur = prev->next; //头结点
int count = 1;
while (pcur->next != pcur) //如果剩余人数大于1
{
if (count == m) //如果已经有m次报数了
{
printf("%d->", pcur->val); //打印出圈人员
prev->next = pcur->next; //让前一个结点直接链接下一个结点
free(pcur); //销毁空间
pcur = prev->next; //报数从下一个结点开始
count = 1; //报数次数回到1
}
else //没到m次报数
{
prev = pcur; //往前移动一位
pcur = pcur->next; //往前移动一位
count++; //计数器加1
}
}
printf("%d", pcur->val); //打印最后一个出圈人员
free(pcur); //销毁空间
}
int main()
{
int n = 0, m = 0;
printf("请输入n和m的值:\n");
scanf("%d%d", &n, &m);
ysf(n, m);
return 0;
}