for循环步长_#图解+动画 数据结构-循环链表:约瑟夫环问题(C语言实现)

b3d97050bb87aa3f79c0f402f4f7a213.png

什么是约瑟夫环问题?

我们先了解一段历史。

Josephus是著名的犹太历史学家

在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。

问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

简化问题:

简单来说,就是M个人围成一圈,第N个人从1开始报数,每次报到Q的人将被杀掉,下一个人接着从1开始报,再次报到Q,如此反复。

最后剩下的一个,就是幸存者。

7a14d5f10397cf839db877c66a14f3f1.png

分析:

解决这个经典的算法问题,有很多种解法,其中公式法是效率最高的。但我用的是单向循环链表。如果人数规模很小倒还好,但如果成千上万的规模,甚至更大。这个方法就会显得很笨。

解决这个问题,只需要三步。

准备工作:

你需要包含头文件,定义结构体。

#include 

8129cca494bff7d7e40b586b169210c1.png
节点

第一步:

初始化线性表

根据输入的总人数M,依次编号,循环创建链表。

// 初始化线性表

98f9d151eef0012830b13bb2148fb9c8.png
初始化循环链表

2b733eb1ada658a5e9af2ecec6cb55fc.png
调试观察

第二步:

从头节点遍历到指定的开始节点

// 链表遍历到开始位置

1c34c92431bcaca6714b88eda762cb31.png

31fb072230abc19581be29fbe034c7af.png
调试观察

第三步:

固定步长循环删除节点

//循环删除节点
7108d4f7ecd3bfb910525b32016c9523.png
单向循环链表动画演示https://www.zhihu.com/video/1235880461672853504

8df766cb679a581144a04fd9898820b1.png
调试观察

main():

当然你也可以不用像我这样,你自己简化喽!

int 

可以发现,用循环链表解决约瑟夫环问题是比较傻瓜的,不需要什么奇技银巧,你只需要一五一十:

  1. 造节点
  2. 找节点
  3. 删节点

就完事儿了。


运行结果:

de799bc61efa0eab064b0f794b683862.png
运行截图

最终代码:

#include 
fe457d8c35eb2f0dc6af36baa6bf2460.png
单向循环链表动画演示https://www.zhihu.com/video/1235887925940088832

1f90711360cb07f0667a83961bcc475b.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值