判斷鍊錶是否有環

2021-09-10 02:16:28 字數 1779 閱讀 5476

給定乙個單鏈表,只給出頭指標h:

解法:使用兩個slow, fast指標從頭開始掃瞄鍊錶。指標slow 每次走1步,指標fast每次走2步。如果存在環,則指標slow、fast會相遇;如果不存在環,指標fast遇到null退出。

public class linklistutli 

public static boolean hascircle(lnode l)

return false;}}

證明:

首先,如果存在環,那麼快指標和慢指標一定會同時進入到環中。假設當slow指標剛進入環時,fast指標所在的結點編號是a(現在只考慮環中的結點),slow指標所在結點編號是k+a,那麼就環展開就像如下圖所示:

由於slow和fast指標都是在環中的,所以可以將環展開的直線無限延伸。如果沒有限制,slow和fast指標可以在環中無限的走下去。

​ 假如說是fast和slow指標可以相遇,且相遇的位置為k+m+a(其中m表示slow指標進入環後走了m步就和fast指標相遇了),那麼m一定是有解的。

我們簡化一下,假設a的位置就是0:

由於slow指標從k結點走了m步就和fast指標相遇了,則一定有下面的等式成立:

k+m=2m

slow指標走了m步,會到達k+m結點處,相應的fast走了m步會到達2m結點,由於是兩個指標走了m步相遇,所以一定有上面的等式成立。由等式可知,m一定是有解的,且m=k

0到k的距離和k到k+m的距離是相同的,而0到k+m是fast指標走的距離,正好slow的2倍。

也就是,如果沒有環,一定不會相遇(fast一定會在前面,slow永遠追不上);有環,一定會在k+m處相遇(將環無限延長n倍)。

在環上相遇後,記錄第一次相遇點為pos,之後指標slow繼續每次走1步,fast每次走2步。在下次相遇的時候fast比slow正好又多走了一圈,也就是多走的距離等於環長。

設從第一次相遇到第二次相遇,設slow走了len步,則fast走了2*len步,相遇時多走了一圈:

環長=2*len-len。

第一次碰撞點pos到連線點join的距離=頭指標到連線點join的距離,因此,分別從第一次碰撞點pos、頭指標head開始走,相遇的那個點就是連線點。

在環上相遇後,記錄第一次相遇點為pos,連線點為join,假設頭結點到連線點的長度為lena,連線點到第一次相遇點的長度為x,環長為r。

第一次相遇時,slow走的長度 s = lena + x;

第一次相遇時,fast走的長度 2s = lena + n*r + x;

所以可以知道,lena + x = nr;  lena = nr -x; (理解:lena = n*(r-1) 【保證回到pos】 + n-x【保證剩下的距離正好到達join】)

上述2中求出了環的長度;3中求出了連線點的位置,就可以求出頭結點到連線點的長度。兩者相加就是鍊錶的長度。

對快慢指標的理解:如果沒有環,快指標一定先走完,兩個指標不會相遇;如果有環,那麼最多只有乙個環,並且兩個指標遲早都會進入環,假定環的長度為l,當慢指標進入環之後,快指標每次能向前追一步距離,最多只要l-1步就能追上慢指標所以可以用兩個指標是否相遇來判斷是否有環。

參考:

如何判斷鍊錶是否有環 鍊錶是否有環的判斷

對於鍊錶是否存在環,有三個問題需要考慮 1.是否有環 2.入環節點 3.環的長度 第一種方法快慢指標法,也稱之為龜兔演算法,設定兩個指標,慢指標和快指標。最開始均指向鍊錶的頭節點,之後,快指標每次後移兩個節點,慢指標每次後移乙個節點。1.如果快指標指向空,則鍊錶無環 2.若快指標和慢指標再次指向乙個...

判斷鍊錶是否有環

1.如何判斷是否有環?如果有兩個頭結點指標,乙個走的快,乙個走的慢,那麼若干步以後,快的指標總會超過慢的指標一圈。2.如何計算環的長度?第一次相遇 超一圈 時開始計數,第二次相遇時停止計數。3.如何判斷環的入口點 碰撞點p到連線點的距離 頭指標到連線點的距離,因此,分別從碰撞點 頭指標開始走,相遇的...

判斷鍊錶是否有環

單向鍊錶是最常用的資料結構之一,因此總結其常見的問題及其解決方案是很有意義的。問題1 如何判斷乙個單向鍊錶是否有環?如果有,如何找到其入口節點的指標?演算法思想 用兩個指標p1,p2同時指向鍊錶的頭部,p1一次移動一步,p2一次移動兩步,如果最終p1和p2重合則說明鍊錶有環,如果p2走到空指標 鍊錶...