环形链表的约瑟夫问题

前言

大家好呀,我是Humble,今天要分享的内容是环形链表的约瑟夫问题

说到链表,约瑟夫问题(约瑟夫环)绝对是一个经典的算法题,下面就让我们一起看一下吧~

环形链表的约瑟夫问题_第1张图片

正文开始前,我们先看一个小小的故事,借此引出主题,如果能勾起大家学习的兴趣就太好啦~


据说历史上有过这样的故事:在罗马人占领乔塔帕特后,39个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式:

41个人排成⼀圈,由第1个人开始报数,每报数到第3人,该人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止


然而约瑟夫和他的朋友并不想遵从。约瑟夫要他的朋友先假装遵从,他将朋友与自己安排在
第16个与第31个位置,于是逃过了这场死亡游戏


好,看完这个故事,不知道你有什么感想?下面我们回归正题,来做一下有这段轶事衍生出的约瑟夫问题吧~


正文

环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)

题目描述:

编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开

下一个人继续从 1 开始报数。

n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?

环形链表的约瑟夫问题_第2张图片

环形链表的约瑟夫问题_第3张图片

对于这道题目,Humble的思路是:
1.根据n来创建不带头的单向循环链表

2.逢m删除当前节点

实现的代码如下:

//为了方便,我们另外封装了两个函数,
//一个用来申请新的节点,一个用来创建不带头单向循环链表~

typedef struct ListNode ListNode;//偷个懒,将struct ListNode重命名为ListNode,嘿嘿

ListNode* BuyNode(int x)
{
   ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));

   newNode->val = x;
   newNode ->next = NULL;
   
   return newNode;
}

ListNode* createlist(int n)
{
    ListNode* phead = BuyNode(1);
    ListNode* ptail = phead;
    for (int i =2;i<=n;i++)
    {
        ptail->next = BuyNode(i);
        ptail = ptail->next;
    }
     ptail->next = phead;//让链表构成环

     return ptail;//返回尾节点

}

int ysf(int n, int m )
 {
   ListNode* prev = createlist(n);//前驱,因为链表是循环的所以初始放在尾节点
   ListNode * head = prev->next;
   ListNode* pcur  = head;

   int count = 1;//计数;

   while (pcur->next != pcur)
   {
       if(count == m)
       {
        prev->next = pcur->next;
        free(pcur);
        pcur =  prev->next;
        count = 1;
       }
        
        else 
        {
          prev  = pcur;
          pcur = pcur->next;
          count++;
        }

   }

//循环结束后,此时的pcur节点就是幸存下来的唯一的节点了
return pcur->val; //输出幸存者的编号
  
}

运行结果如下:
环形链表的约瑟夫问题_第4张图片

结语

好了,今天关于约瑟夫环的分享就到这里了,如果对大家有帮助就太好啦~

在学习编程的道路上Humble与各位同行,加油吧各位!

最后希望大家点个免费的赞或者关注吧(感谢感谢),也欢迎大家订阅我的专栏

让我们在接下来的时间里一起成长,一起进步吧!

e0d3d2143b284925a6e6d82b6cd73662.png

你可能感兴趣的:(C语言进阶之数据结构,链表,算法,数据结构,c语言,开发语言)