Floyd's Tortoise and Hare循环检测算法
Floyd’s Tortoise and Hare
Reference: Cycle detection
循环检测问题(Cycle detection)
假设有限集合S={0,1,2,4,5,6,7,8},同时有函数f从集合S映射到集合S。如果从某X0=2开始连续调用f,显然会生成一系列数值。
2,0,6,3,1,6,3,1,6,3,1 …
熟悉逻辑设计的同学可能会很眼熟,这个和有限状态机是一个道理,集合元素数目有限,从某个元素μ开始,序列会以周期λ循环,这里μ=2,λ=3。序列从0开始计数。当然这个起始点不一样,μ与λ可能是不同的。
循环检测就是在类似的问题中找出μ与λ。
CS中通常会碰到此类问题,获得某序列数据,比如说链表,希望在占用尽可能小的存储空间的条件下检测出该链表是否循环,得出μ与λ。
朴素的思想是沿着链表遍历,将途经结点地址保存下来,每加入一个结点进行一轮比较。在μ+λ次读写比较之后,如果该链表是循环的,则开始出现相同结点地址,可以显然判断μ与λ,但这样的算法空间复杂度是O(μ+λ)。对于这样一个问题,代价过高。
Floyd’s Tortoise and Hare算法是一个只需要使用两个指针的指针算法(pointer algorithm),通过两个前进速度不同的指针,类比伊索寓言中的龟兔,可完成以上任务。算法的实现相当简单,这也就意味着算法的设计相当精妙。本文主要就是致敬数学大佬们超凡的思维能力。
算法原理
存在某序列Xi,如果是循环的,对于所有i>μ,k>0,有Xi=Xi+kλ,这个不难理解,就是把循环的定义专业表达了一下。重点是下面。
那么存在k>0使得i=kλ>μ成立,即存在Xi=X2i。
如果可以得到 i 的值,从头遍历链表通过判断if(x[j]==x[j+i])即可获知μ,由μ向后遍历比较即可得知λ。若是不存在Xi=X2i,链表就已经结束,即可获知不循环。如何得知这个 i 是不难的,难的是我一下想不出这个数学原理。
首先为什么要用kλ来表示周期?我们通常使用最小周期λ。因为我们需要保证i>μ成立,所以必须放大周期!
为什么要找出Xi=X2i 这个关系?因为这样我们可以用一个比较简单的办法找出 i !
可能我脑子不太好使,这些变换摆出来是看得懂,想的时候是完全没有方向。学数学那阵就最讨厌这变换那变换的了,也太需要灵性了吧。
算法实现
- 找两个指针tortoise(龟)和hare(兔),初始化指向链表头指针head;
- 兔指针前进两结点。如果还未完成就指向NULL,链表结束,无循环;
- 龟指针前进一结点。不需要空指针检测;
- 如果龟兔指针指向同一结点,则链表循环。否则返回2。
int ll_has_cycle(node *head) {node *tortoise, *hare;tortoise = head;hare = head;//Special case checkif (head == NULL)return 0;//Advance hare by two nodes
STEP2:if (hare->next == NULL)return 0;elsehare = hare->next;if (hare->next == NULL)return 0;elsehare = hare->next;//Advance tortoise by one nodetortoise = tortoise->next;if (tortoise == hare)return 1;elsegoto STEP2;
}
上面的实现易于理解,但不是一个好的实现,尽量避免goto的出现。
int ll_has_cycle(node *head) {node *tortoise, *hare;tortoise = head;hare = head;if (head == NULL)return 0;while (!(tortoise == hare)){//Advance hare by two nodesif (hare->next == NULL)return 0;elsehare = hare->next;if (hare->next == NULL)return 0;elsehare = hare->next;//Advance tortoise by one nodetortoise = tortoise->next;}return 1;
}
这个只检测了是否循环,主要是一个对于C语言指针的练习。
萌新博主,以后也许会更新一些关于RISC-V或者深度学习的相关体会,也许吧。。。
Floyd's Tortoise and Hare循环检测算法相关推荐
- floyd算法 每一层循环_链接列表循环检测– Floyd的循环查找算法
floyd算法 每一层循环 In this tutorial, we'll be discussing a very popular algorithm which is used to detect ...
- 车道线检测算法经典编程
车道线检测算法经典编程 车道线曲线拟合算法编程 计算经过(50,50),(90,120),(70,200)三点的Catmull_Rom样条曲线. IplImage* img = cvCreateIma ...
- 时序预测竞赛之异常检测算法综述
本文将介绍在时间序列预测相关问题中常见的异常检测算法,可以很大程度上帮助改善最终预测效果. 异常分类 时间序列的异常检测问题通常表示为相对于某些标准信号或常见信号的离群点.虽然有很多的异常类型,但是我 ...
- 使用PyTorch从零开始实现YOLO-V3目标检测算法 (四)
原文:https://blog.csdn.net/u011520516/article/details/80228130 点击查看博客原文 这是从零开始实现YOLO v3检测器的教程的第4部分,在上一 ...
- 使用PyTorch从零开始实现YOLO-V3目标检测算法 (三)
原文:https://blog.csdn.net/u011520516/article/details/80216009 点击查看博客原文 这是从零开始实现YOLO v3检测器的教程的第3部分.第二部 ...
- 目标检测算法综述 | 基于候选区域的目标检测器 | CV | 机器视觉
目标检测算法综述 | 基于候选区域的目标检测器 | CV | 机器视觉 滑动窗口检测器 自从 AlexNet 获得 ILSVRC 2012 挑战赛冠军后,用 CNN 进行分类成为主流.一种用于目标检测 ...
- Gosper 的序列 循环检测
// 高效程序的奥秘hacker's delight Henry S. Warren, Jr. 著冯速译 // 第5 章位计数5.4 后缀0 计数 // 假设序列X0, X1, X2, ... 是由X ...
- 【图像处理】纹理检测算法
图像纹理检测算法 LBP检测算法 原文链接:https://blog.csdn.net/tiandijun/article/details/45561981 https://blog.csdn.net ...
- 【时间序列】时序预测竞赛之异常检测算法综述
本文将介绍在时间序列预测相关问题中常见的异常检测算法,可以很大程度上帮助改善最终预测效果. 异常分类 时间序列的异常检测问题通常表示为相对于某些标准信号或常见信号的离群点.虽然有很多的异常类型,但是我 ...
- 基于python的HOG+SVM目标检测算法实现
目录 一.场景需求解读 二.HOG算法简介 三.SVM算法简介 四.基于HOG的目标检测算法训练流程 五.目标检测代码实现 六.非极大值抑制(NMS)简介及代码实现 七.NMS效果展示与分析 八.思维 ...
最新文章
- double和float计算精度不准的问题
- sudo配置文件详解及实战
- ABAP和Java里关于DEFAULT(默认)机制的一些语言特性
- 在myeclipse文件中如何创建properties类型的文件,从而连接数据库
- IE6 IE7 IE8(Q) 不支持 JSON 对象
- 快速了解上市公司年报
- cmake (2)其他指令
- 设计模式--访问器(Visitor)模式
- CS231n官方笔记授权翻译总集篇发布
- java递归算法实现
- windows API 开发飞机订票系统 图形化界面 (二)
- Error generating final archive: Debug Certificate expired on 的错误解决方法
- MySQL把多条数据给汇总成一条数据
- Vmware中win7联网
- 学好UI设计必备软件
- Unity - 搬砖日志 - 打开项目时崩溃/或是运行不起unity的日志
- 人工智能 —— 语义网络推理
- 2020年6月7日日记
- RTOS内功修炼记(十) | 深度解析RTOS内核上下文切换机制
- 大数据教程【05.01】--Python 数据分析简介