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

来源:互联网 发布:java与xml 第三版 pdf 编辑:程序博客网 时间:2024/05/16 16:08

参考资料:

1. 维基百科

https://zh.wikipedia.org/w/index.php?title=Floyd判圈算法&redirect=no

2. http://blog.csdn.net/thestoryofsnow/article/details/6822576


Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),该算法由美国科学家罗伯特·弗洛伊德发明。

算法作用

可以在有限状态机、迭代函数或者链表上判断是否存在环,以及求出该环的起点与长度的算法。

算法原理

如果存在环,那么从同一个起点(即使这个起点不在某个环上)处,同时开始以不同速度前进的2个指针必定会在某个时刻相遇。

算法描述

(1)求环

初始状态下,假设已知某个起点节点为节点S。现设两个指针t和h,将它们均指向S。

同时让t和h往前推进,h的速度为t的2倍),直到h无法前进,即到达某个没有后继的节点时,就可以确定从S出发不会遇到环。反之当t与h再次相遇时,就可以确定从S出发一定会进入某个环,设其为环C。(h和t推进的步数差是环长的倍数)

(2)求环的长度

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

(3)求环的起点

为了求出环C的起点,只要令h仍均位于节点M,而令t返回起点节点S。随后,同时让t和h往前推进,且速度相同。持续该过程直至t与h再一次相遇,此相遇点就是环C的一个起点。

why?

假设出发起点到环起点的距离为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为圈长度的倍数,可以理解为指针从链表起点出发,走到环起点,然后绕环转了几圈,所以第二个指针也必然在环的起点。即两者相遇点就是环的起点。


伪代码

<span style="font-family:Times New Roman;font-size:14px;"> 1  t := &S 2  h := &S                                        //令指针t和h均指向起点节点S。 3  repeat 4      t := t->next 5      h := h->next 6      if h is not NULL                                //要注意这一判断一般不能省略 7              h := h->next 8  until t = h or h = NULL 9  if h != NULL                                       //如果存在环的话 10     n := 0 11     repeat                                              //求环的长度 12             t := t->next 13             n := n+1 14     until t = h 15     t := &S                                     //求环的一个起点 16     while t != h 17             t := t->next 18             h := h->next 19     P := *t</span>

算法复杂度

(1)时间复杂度

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

(2)空间复杂度

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


应用

对于有限状态机与链表,可以判断从某个起点开始是否会返回到访问过运行过程中的某个状态和节点。

对于迭代函数,可以判断其是否存在周期,以及求出其最小正周期。



1 0
原创粉丝点击