#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int num_data;
struct Node* next_ptr;
} SLTNode;
void test01()
{
//n个人,数到m个数淘汰一个
int n = -1, m = -1;
//scanf()函数获取两个变量的值,出于安全考虑,加个if检测
if(2 != scanf("%d%d",&n,&m)) { exit(-1); };
//创建一个头节点
SLTNode * head = (SLTNode*)malloc(sizeof(struct Node));
//出于对malloc的安全性考虑,加个if检测
if(NULL == head) {exit(-1);}
head->next_ptr = NULL;//头节点的指针域赋NULL值
SLTNode* now = head;//定义一个临时的结构体指针,指向链表中逻辑理解的最后一个节点
for(int i = 0; i < n; ++i)
{
if(0 == i)
{
head->num_data = 1;
}
else
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if(NULL == newnode) {exit(-1);}//如上,加个if检测
newnode->num_data = i + 1;//给新节点赋数据值
newnode->next_ptr = NULL;//先初始化为NULL
now->next_ptr = newnode;//最后一个节点now的next_ptr指向新节点
now = newnode; //此时新节点就是链表在逻辑上的最后一个节点
//now指向最后一个节点
}
}
//尾结点的next_ptr指向头结点的地址,形成一个圈(循环链表)
now->next_ptr = head;
//elim淘汰单词缩写
SLTNode * elim_cur = head; //指向淘汰的人(节点)的指针(地址),从头结点开始数
SLTNode* elim_pre = now; //指向淘汰的人(节点)的前一个指针(地址)
int count_nums = 0; //每当一个人数了数后,就++,知道数完数 ++后等于m就重置为0
//当只剩一个的时候自己指向自己,直接退出再另外做出局操作
while(elim_cur!= elim_cur->next_ptr)
{
//先报数——这里的报数是虚拟报数(每个人心中按规律对于自己应该报什么),一旦为m值,就出局
++count_nums;
//检测看看有没有报数报到m
if(m == count_nums)
{
//如果有就先输出这个人的编号
printf("%d ",elim_cur->num_data);
//然后在把其前面一个人(节点)的指针域指向这个被淘汰的下一个节点的地址
elim_pre->next_ptr = elim_cur->next_ptr;
//然后真正淘汰,直接free
free(elim_cur);
//然后进入下一轮,有刚刚被淘汰的下一个人开始重新报数
elim_cur = elim_pre->next_ptr;
//重置count_nums为0
count_nums = 0;
}
else
{
//没有报到m的,下一个接着报数
elim_pre = elim_cur;
elim_cur = elim_cur->next_ptr;
}
}
if(elim_cur == elim_cur->next_ptr)
{
printf("%d ",elim_cur->num_data);
free(elim_cur);
}
head = now = elim_pre = elim_cur = NULL;//置空
}
int main()
{
test01();
return 0;
}
洛谷题库p1996——约瑟夫问题(c语言实现)(有注释)
最新推荐文章于 2024-04-20 13:16:42 发布