Floyd判圈算法

Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,求出该环的起点与长度的算法。该算法据高德纳称由美国科学家罗伯特·弗洛伊德发明,但这一算法并没有出现在罗伯特·弗洛伊德公开发表的著作中。
  如果有限状态机、迭代函数或者链表上存在环,那么在某个环上以不同速度前进的2个指针必定会在某个时刻相遇。同时显然地,如果从同一个起点(即使这个起点不在某个环上)同时开始以不同速度前进的2个指针最终相遇,那么可以判定存在一个环,且可以求出2者相遇处所在的环的起点与长度。

算法描述:

判断是否存在环路:

如果有限状态机、迭代函数或者链表存在环,那么一定存在一个起点可以到达某个环的某处(这个起点也可以在某个环上)。
初始状态下,假设已知某个起点节点为节点S。现设两个指针t和h,将它们均指向S。接着,同时让t和h往前推进,但是二者的速度不同:t每前进1步,h前进2步。只要二者都可以前进而且没有相遇,就如此保持二者的推进。当h无法前进,即到达某个没有后继的节点时,就可以确定从S出发不会遇到环。反之当t与h再次相遇时,就可以确定从S出发一定会进入某个环,设其为环C。如果确定了存在某个环,就可以求此环的起点与长度。

求解环路的长度:
上述算法刚判断出存在环C时,显然t和h位于同一节点,设其为节点M。显然,仅需令h不动,而t不断推进,最终又会返回节点M,统计这一次t推进的步数,显然这就是环C的长度。

求解环路的起点:
为了求出环C的起点,只要令h仍均位于节点M,而令t返回起点节点S,此时h与t之间距为环C长度的整数倍。随后,同时让t和h往前推进,且保持二者的速度相同:t每前进1步,h前进1步。持续该过程直至t与h再一次相遇,设此次相遇时位于同一节点P,则节点P即为从节点S出发所到达的环C的第一个节点,即环C的一个起点。

对于环路起点算法的解释:

假设出发起点到环起点的距离为m,已经确定有环,环的周长为n,(第一次)相遇点距离环的起点的距离是k。那么当两者相遇时,慢指针(t)移动的总距离i = m + a * n + k,快指针(h)的移动距离为2i,2i = m + b * n + k。其中,a和b分别为t和h在第一次相遇时转过的圈数。让两者相减(快减慢),那么有i = (b - a) * n。即i是圈长度的倍数。
将一个指针移到出发起点S,另一个指针仍呆在相遇节点M处两者同时移动,每次移动一步。当第一个指针前进了m,即到达环起点时,另一个指针距离链表起点为i + m。考虑到i为圈长度的倍数,可以理解为指针从链表起点出发,走到环起点,然后绕环转了几圈,所以第二个指针也必然在环的起点。即两者相遇点就是环的起点。

    t := &S
    h := &S                                        //令指针t和h均指向起点节点S。
    repeat
        t := t->next
        h := h->next
        if h is not NULL                                //要注意这一判断一般不能省略
                h := h->next
    until t = h or h = NULL
    if h != NULL                                       //如果存在环的话
        n := 0
        repeat                                              //求环的长度
                t := t->next
                n := n+1
        until t = h
        t := &S                                     //求环的一个起点
        while t != h
                t := t->next
                h := h->next
        P := *t

  

算法复杂度:

时间复杂度:注意到当指针t到达环C的一个起点节点P时(此时指针h显然在环C上),之后指针t最多仅可能走1圈。若设节点S到P距离为 m,环C的长度为  n,则时间复杂度为 O(m+n),是线性时间的算法。

空间复杂度:仅需要创立指针t、指针h,保存环长n、环的一个起点P。空间复杂度为 O(1),是常数空间的算法。

时间: 2024-10-24 22:44:13

Floyd判圈算法的相关文章

[LeetCode] 287. Find the Duplicate Number(Floyd判圈算法)

传送门 Description Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. Note: You mu

uva 11549计算器谜题(floyd判圈算法)

 题意:有个老式计算器,每次只能记住一个数字的前n位.现在输入一个整数k,然后反复平方,一直做下去,能得到的最大数是多少.例如,n=1,k=6,那么一次显示:6,3,9,1... 思路:这个题一定会出现循环,所以一个个模拟,遇到相同的就再之前所有数中找最大的输出即可. 最容易想到的就是set判重,一开始k直接生算每次除十......超时 然后看了书,用string,ac,很方便但是时间达到了4s,果然string和stringstream好慢啊......... 又改成了记录k*k的每一位,

SGU 455 Sequence analysis(Cycle detection,floyd判圈算法)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=455 Due to the slow 'mod' and 'div' operations with int64 type, all Delphi solutions for the problem 455 (Sequence analysis) run much slower than the same code written in C++ or Java. We do not gua

sgu 455. Sequence analysis (floyd 判圈算法,O(1)空间复杂度求循环节)

455. Sequence analysis Time limit per test: 1 second(s)Memory limit: 4096 kilobytes input: standardoutput: standard Due to the slow 'mod' and 'div' operations with int64 type, all Delphi solutions for the problem 455 (Sequence analysis) run much slow

leetcode202(Floyd判圈算法(龟兔赛跑算法))

Write an algorithm to determine if a number is "happy". 写出一个算法确定一个数是不是快乐数. A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat th

UVa 11549 计算器谜题(Floyd判圈算法)

https://vjudge.net/problem/UVA-11549 题意: 有一个老式计算器,只能显示n位数字,输入一个整数k,然后反复平方,如果溢出的话,计算器会显示结果的最高n位.如果一直这样做下去,能得到的最大数是多少? 思路: 这个肯定是会循环的. 比较普通的做法就是用set来判断是否出现过来终止循环. 另一个高效算法:Floyd判圈算法!! 想象一下,假设有两个小孩子在一个“可以无限向前跑”的跑道上赛跑,同时出发,但其中一个孩子的速度是另一个两倍.如果跑到是直的,跑得快的小孩永远

Floyd判圈算法(判断链表是否含环)

Floyd判圈算法 简介 Floyd判圈算法,也称龟兔赛跑算法,可用于判断链表.迭代函数.有限状态机是否有环.如果有,找出环的起点和大小.时间复杂度O(n),空间复杂度O(1). 可以先思考一下,假设有一个圆形的跑道周长为\(C\),A和B从同一个起点,分别以\(v\)和\(2v\)的速度同向出发,可以知道,因为B比A跑得快而且跑道是环形的,所以接下来一定存在某一时刻,B和A相遇,这时候,B跑过的总距离\(S_B\)减去A跑的总距离\(S_A\)一定是\(C\)的整数倍.即: \(S_B-S_A

Floyd判圈算法(判断是否有环)

介意转吗博主~~http://blog.csdn.net/thestoryofsnow/article/details/6822576,我知道不介意啦~ 问题:如何检测一个链表是否有环,如果有,那么如何确定环的起点. 龟兔解法的基本思想可以用我们跑步的例子来解释,如果两个人同时出发,如果赛道有环,那么快的一方总能追上慢的一方.进一步想,追上时快的一方肯定比慢的一方多跑了几圈,即多跑的路的长度是圈的长度的倍数. 基于上面的想法,Floyd用两个指针,一个慢指针(龟)每次前进一步,快指针(兔)指针每

UVA11549 计算机谜题(Floyd判圈算法)

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<set> 7 #include<sstream> 8 using namespace std; 9 /*int next1(int n,int k) 10 { 11 stringstream ss; 12