Floyd判圈演算法(龜兔賽跑演算法)

2021-07-13 07:19:28 字數 1738 閱讀 8289

一、演算法簡述

floyd判圈演算法(floyd cycle detection algorithm),又稱龜兔賽跑演算法(tortoise and hare algorithm),是乙個可以在有限狀態機、迭代函式或者鍊錶上判斷是否存在環,以及判斷環的起點與長度的演算法。

二、基本思路

在某種關係下,頂點 i 到 k 拓撲有序,頂點 k 到 j 也是相同的順序,那麼 i 和 j 也存在這個順序。要是某乙個頂點出現了自己到自己的環,那麼圖中就有環,但是這種方法複雜度高一些,沒有檢測頂點出度或者dfs的方法快,但是非常簡單。

三、問題

如何檢測乙個鍊錶是否有環,如果有,那麼如何確定環的起點和環的長度。

四、解決方案

1)判斷是否有環?

龜兔解法的基本思想可以用我們跑步的例子來解釋,如果兩個人同時出發,如果賽道有環,那麼快的一方總能追上慢的一方。進一步想,追上時快的一方肯定比慢的一方多跑了幾圈,即多跑的路的長度是圈的長度的倍數。

基於上面的想法,floyd用兩個指標,乙個慢指標(龜)每次前進一步,快指標(兔)指標每次前進兩步(兩步或多步效果時等價的,只要乙個比另乙個快就行)。如果兩者在煉表頭以外的某一點相遇(即相等)了,那麼說明鍊錶有環,否則,如果(快指標)到達了鍊錶的結尾,那麼說明沒壞。

(2)求環的長度

相遇的時候,一定已經在環上了,然後兩個人只要再次在環上接著跑,再次相遇的時候(也就是所謂的套圈),跑的快的那個人就比跑的慢的人整整多跑了一圈,所以環的長度也就出來了。

(3)如何確定環的起點

環的檢測用上述原理,接下來我們來看一下如何確定環的起點,這也是floyd解法的第二部分。方法是將其中乙個指標移到鍊錶起點,兩者同時移動,每次移動一步,那麼兩者相遇的地方就是環的起點。

解析:

首先假設第一次相遇的時候慢指標走過的節點個數為i,設煉表頭部到環的起點的長度為m,環的長度為n,相遇的位置與起點與起點位置距離為k。

於是有:

i = m + a * n + k

其中a為慢指標走的圈數。

因為快指標的速度是慢指標的2倍,於是又可以得到另乙個式子:

2 * i = m + b * n + k

其中b為快指標走的圈數。

兩式相減得:

i = ( b - a ) * n

也就是說i是圈長的整數倍。

這是將其中乙個節點放在起點,然後同時向前走m步時,此時從頭部走的指標在m位置。而從相遇位置開始走的指標應該在距離起點i+m,i為圈長整數倍,則該指標也應該在距離起點為m的位置,即環的起點。

例項程式如下:

int *head = list.gethead();

if (head != null)

fastptr = fastptr->next->next;

slowptr = slowptr->next;

} while (fastptr != slowptr);

//確定環的起點

slowptr = head;

while(slowptr != fastptr)

cout<<"the starting point of the cycle is "<

龜兔賽跑演算法(Floyd判圈演算法)

參考資料 1.維基百科 判圈演算法 redirect no 2.floyd判圈演算法 floyd cycle detection algorithm 又稱龜兔賽跑演算法 tortoise and hare algorithm 該演算法由美國科學家羅伯特 弗洛伊德發明。可以在有限狀態機 迭代函式或者鍊...

Floyd判圈演算法

參考 判斷鍊錶中是否有環 大概就是說兩個指標首先都指向鍊錶的首部,然後乙個每次走一步,乙個每次走兩步,如果有環,那麼慢的肯定能夠追上快的,否則快的就會先到達終點。求環的長度 兩個指標重合時,快的停止,慢的每次走一步,計算圈的長度。求環的起點 if head null slowptr slowptr ...

floyd判圈演算法

floyd判圈演算法又稱龜兔賽跑演算法 兩個指標 p1,p2 p1 每次向後跳一次 p2 每次向後跳兩次 顯然,如果 p1,p2 相遇才有環 現在我們想求環長和環的起點.設起點到環的距離為 len 環的起點離相遇點距離 rem 設兩個指標分別走了 p,q 步 那麼,p len rem a l,q l...