C语言:约瑟夫环问题详解

这篇具有很好参考价值的文章主要介绍了C语言:约瑟夫环问题详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言
哈喽,宝子们!本期为大家带来一道C语言循环链表的经典算法题(约瑟夫环)。

1.什么是约瑟夫环

据说著名历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人拼成一个圆圈,由第一个人开始报数,每报数到第三人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
这道题的原理也是一样的,来看看这道题长什么样吧。
描述:
编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。下一个人继续从 1 开始报数。
n - 1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?
示例1:
输入:5, 2
返回值:3
说明:
开始5个人 1,2,3,4,5 ,从1开始报数,1->1,2->2编号为2的人离开。
1,3,4,5,从3开始报数,3->1,4->2编号为4的人离开。
1,3,5,从5开始报数,5->1,1->2编号为1的人离开。
3,5,从3开始报数,3->1,5->2编号为5的人离开。
最后留下人的编号是3。

2.解决方案思路

既然是循环的报数,那我们就可以用我们所学过的单链表来解决这道题。

  1. 那假设我们有n个人,就要创建n个节点,首先创建一个节点,然后同时用两个指针指向这个节点,这个节点既是头指针head,也是尾指针ptail
  2. 然后把这个创建的过程用一个函数封装起来,调用函数来创建剩下的几个节点,每次调用完就让ptail的next指针指向我们新创建的节点,然后更新ptail指针的位置。
  3. 此时,我们的节点已经全部创建完成了,但是最重要的一步,就是要让我们的链表形成一个环,最后让尾指针的next指针指向我们的head
  4. 接着就是报数的实现需要有循环,报数要用一个计数器count来记录,当count等于m的时候,就要删除当前这个节点,然后更改头指针和尾指针的位置,最后直到头指针指向自己,此时指针里val的值就是最终留下来的值。
    C语言:约瑟夫环问题详解,c语言,开发语言,经验分享

3.创建链表头结点

//创建头链表
ListNode* ListBuyNode(int x)
{
    ListNode* newhead = (ListNode*)malloc(sizeof(ListNode));
    //动态申请内存失败
    if (newhead == NULL)
    {
        exit(1);
    }
    //申请成功
    newhead->val = x;
    newhead->next = NULL;
    return newhead;
}

4.创建循环链表

//创建带环链表
ListNode* CreateCircle(int n)
{
    //先创建第一个节点
    ListNode* head = ListBuyNode(1);
    ListNode* ptail = head;
    for (int i = 2; i <= n; i++)
    {
        //用尾插的方式把节点连接起来
        ptail->next = ListBuyNode(i);
        ptail = ptail->next;//更新尾节点位置
    }
    //收尾相连,链表成环
    ptail->next = head;
    return ptail;
}

5.删除链表

//当链表中只有一个节点的情况就是循环的终止条件
while (pcur->next != pcur)
{
    if (count == m)
    {
        //销毁pcur节点
        prev->next = pcur->next;
        free(pcur);
        pcur = prev->next;
        count = 1;
    }
    else
    {
        //此时不需要销毁节点
        prev = pcur;
        pcur = pcur->next;
        count++;
    }
}

6.完整代码实现

//定义节点
struct ListNode
{
    int val;
    struct ListNode* next;
};
typedef struct ListNode ListNode;//类型重定义
//创建头链表
ListNode* ListBuyNode(int x)
{
    ListNode* newhead = (ListNode*)malloc(sizeof(ListNode));
    if (newhead == NULL)
    {
        exit(1);
    }
    newhead->val = x;
    newhead->next = NULL;
    return newhead;
}
//创建带环链表
ListNode* CreateCircle(int n)
{
    //先创建第一个节点
    ListNode* head = ListBuyNode(1);
    ListNode* ptail = head;
    for (int i = 2; i <= n; i++)
    {
        ptail->next = ListBuyNode(i);
        ptail = ptail->next;
    }
    //收尾相连,链表成环
    ptail->next = head;
    return ptail;
}
int ysf(int n, int m) 
{
    //1.根据n创建带环链表
    ListNode* prev = CreateCircle(n);//尾指针
    ListNode* pcur = prev->next;//头指针
    int count = 1;
    //当链表中只有一个节点的情况就是循环的终止条件
    while (pcur->next != pcur)
    {
        if (count == m)
        {
            //销毁pcur节点
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
        else
        {
            //此时不需要销毁节点
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
    }
    //此时剩下的最后一个节点里的值就是要返回的值
    return prev->val;
}
int main()
{
    //测试用例
    int win=ysf(5, 2);
    printf("%d", win);
    return 0;
}

如果对你有所帮助的话,别忘了点赞+关注哟❤️!文章来源地址https://www.toymoban.com/news/detail-850274.html

到了这里,关于C语言:约瑟夫环问题详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言数据结构-用链表解决约瑟夫环问题

    只是普通的大学生一枚,不会很牛的技巧和算法,只是在做数据结构作业中的一点感悟和思考。也不知道自己写得对不对,有什么意见和建议都可以直接指出来哦,我虚心接受(低头鞠躬.jpg)...... 试用线性表的链表存储结构来实现约瑟夫(Josephu)问题。约瑟夫问题如下:设有

    2024年02月06日
    浏览(34)
  • C语言---数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(35)
  • 约瑟夫问题

    约瑟夫问题是一个经典的数学问题,也是计算机科学中常见的数据结构和算法题目之一。它的形式是:有n个人站成一排,从第一个人开始报数,每次报到m的人出列,直到所有人都出列为止。请问,最后留下的人原来在什么位置上? 这个问题可以用多种方法解决,其中包括使

    2023年04月09日
    浏览(20)
  • 约瑟夫环问题

    n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。 注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n − 1

    2024年02月02日
    浏览(23)
  • 约瑟夫环问题解决

    单链表 实现 错例 在使用malloc函数开辟的空间中,不要进行指针的移动, 因为一旦移动之后可能出现申请的空间和释放空间大小的不匹配 循环链表 单独创建 逐节点创建 约瑟夫环问题 实现方式一: 实现方式二: 删除节点并建立新链表 实现

    2024年02月02日
    浏览(28)
  • 【数据结构与算法】【约瑟夫问题】还在用递归?教你用链表秒杀约瑟夫

     🎉🎉欢迎光临🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟特别推荐给大家我的最新专栏 《数据结构与算法:初学者入门指南》📘📘 本专栏纯属为爱发电永久免费!!! 这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://su

    2024年02月19日
    浏览(30)
  • 神奇的约瑟夫环(C语言)

    约瑟夫环是一个古老而有趣的问题,它涉及人与人之间的生死较量,引发了人们长久以来的思考和探索。这个问题可以通过不同的方式来解决,每种方式都有其独特的优缺点。 使用数组实现约瑟夫环可以简单直观地表示人员的顺序,但受到数组大小静态限制和数据复制的操作

    2024年02月13日
    浏览(24)
  • 【算法】约瑟夫环问题解析与实现

    约瑟夫环(Josephus Problem)是一个经典的数学问题,涉及一个编号为 1 到 n 的人围成一圈,从第一个人开始报数,报到某个数字 m 的人出列,然后再从下一个人开始报数,如此循环,直到所有人都出列。本篇博客将详细解析约瑟夫环问题,并使用 Python 实现算法。 在约瑟夫环问

    2024年02月06日
    浏览(34)
  • 循环链表解决约瑟夫环问题

    n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。 n个人围成一圈,很容易可以想到用循环链表解决问题,用结点代表每个人,节点的数据域存储人的编号

    2024年02月07日
    浏览(31)
  • 4种方法解决约瑟夫环问题

            约瑟夫环问题是大多数编程初学者必须要跨越的一道坎。在第一次见到它的时候,我还是个刚刚学会循环语句的小蒟蒻,而现在的我已经是深陷图论以及各种其他算法的大蒟蒻了(bushi)。可以说,约瑟夫环问题是我从编程基础向编程思维踏出的重要一步。        

    2024年02月12日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包