Floyd演算法——Cycle detection

來源:互聯網
上載者:User
今天在寢室看了POJ 上一道拓撲排序的題POJ1094 到實驗室之後正好被歐陽看到,跟我說了另外一種演算法Floyd
Warshall 具體參見 http://en.wikipedia.org/wiki/Floyd–Warshall_algorithm 其實就是求任意兩點間的最短路徑的Floyd演算法,這個也能拓展到閉包問題上去。基本思路就是:在某種關係下,頂點i 到k 拓撲有序,頂點k 到 j也是相同的順序,那麼 i 和 j 也存在這個順序。要是某一個頂點出現了自己到自己的環,那麼圖中就有環,但是這種方法複雜度高一些,沒有檢測頂點出度或者DFS的方法快,但是非常簡單。
let dist be a |V| × |V| array  initialized to 0 for each vertex v   dist[v][v] ← 0 for each edge (u,v)   dist[u][v] ← 1  // u,v in order for k from 1 to |V|   for i from 1 to |V|      for j from 1 to |V|         if dist[i][k]  && dist[k][j]  then            dist[i][j]  // i,j in order  for i from 1 to |V|     if dist[i][i] // self circle        // circle detected


不經意發現了連結上有另外一個問題:如何判斷鏈表中是否有環,環的起點和環的長度如何確定。http://en.wikipedia.org/wiki/Floyd's_cycle-finding_algorithm#Tortoise_and_hare 這裡面有很詳細的介紹,但是我沒怎麼看懂(英文太差)後來搜了一下,發現一篇部落格上講的很好。 原帖地址: http://blog.csdn.net/thestoryofsnow/article/details/6822576

問題:如何檢測一個鏈表是否有環,如果有,那麼如何確定環的起點.

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

基於上面的想法,Floyd用兩個指標,一個慢指標(龜)每次前進一步,快指標(兔)指標每次前進兩步(兩步或多步效果是等價的,只要一個比另一個快就行,從後面的討論我們可以看出這一點)。如果兩者在鏈表頭以外的某一點相遇(即相等)了,那麼說明鏈表有環,否則,如果(快指標)到達了鏈表的結尾,那麼說明沒環。

環的檢測從上面的解釋理解起來應該沒有問題。接下來我們來看一下如何確定環的起點,這也是Floyd解法的第二部分。方法是將慢指標(或快指標)移到鏈表起點,兩者同時移動,每次移動一步,那麼兩者相遇的地方就是環的起點。

   這樣做的道理我用解釋。假設起點到環的起點距離為m,已經確定有環,環的周長為n,(第一次)相遇點距離環的起點的距離是k。那麼當兩者相遇時,慢指標移動的總距離為i,i = m + a * n
+ k,因為快指標移動速度為慢指標的兩倍,那麼快指標的移動距離為2i,2i = m + b * n + k。其中,a和b分別為慢指標和快指標在第一次相遇時轉過的圈數。我們讓兩者相減(快減慢),那麼有i = (b - a) * n。即i是圈長度的倍數。利用這個結論我們就可以理解Floyd解法為什麼能確定環的起點。將一個指標移到鏈表起點,另一個指標不變,即距離鏈表起點為i處,兩者同時移動,每次移動一步。當第一個指標前進了m,即到達環起點時,另一個指標距離鏈表起點為i + m。考慮到i為圈長度的倍數,可以理解為指標從鏈表起點出發,走到環起點,然後繞環轉了幾圈,所以第二個指標也必然在環的起點。即兩者相遇點就是環的起點。


 

Python:def floyd(f, x0):   # The main phase of the algorithm, finding a repetition x_mu = x_2mu   # The hare moves twice as quickly as the tortoise   # Eventually they will both be inside the cycle    # and the distance between them will increase by 1 until   # it is divisible by the length of the cycle.   tortoise = f(x0) # f(x0) is the element/node next to x0.   hare = f(f(x0))   while tortoise != hare:       tortoise = f(tortoise)       hare = f(f(hare))   # at this point the position of tortoise which is the distance between    # hare and tortoise is divisible by the length of the cycle.    # so hare moving in circle and tortoise (set to x0) moving towards    # the circle will intersect at the beginning of the circle.   # Find the position of the first repetition of length mu   # The hare and tortoise move at the same speeds   mu = 0   tortoise = x0   while tortoise != hare:       tortoise = f(tortoise)       hare = f(hare)       mu += 1   # Find the length of the shortest cycle starting from x_mu   # The hare moves while the tortoise stays still   lam = 1   hare = f(tortoise)   while tortoise != hare:       hare = f(hare)       lam += 1   return lam, mu

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.