洛谷题库p1996——约瑟夫问题(c语言实现)(有注释)

#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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小艺术生◎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值