如何判斷鍊錶是否有環

2022-08-15 18:12:12 字數 2548 閱讀 2946

這個問題可以衍生出很多擴充套件性的問題:

給定乙個單鏈表,

1.如何判斷是否有環

2.如何知道環的長度

3.如何找到環的入口

4.整個鍊錶的長度是多少

相應的解法如下:

問題1時後面所有問題的根問題,解決這個問題一般用到快慢指標,乙個fast指標,乙個slow指標,兩個指標同時指向單鏈表的頭結點,然後fast指標一次移動兩步,slow指標則一次移動一步,如果最終兩個指標相遇,則說明鍊錶有環,否則無環。

1

bool hascycle(listnode *head)

13else

14return

false;15

if(fast==slow)

16return

true;17

}18return

false

;19 }

那為什麼這樣就能判斷鍊錶中是否存在環呢?

假定單鏈表的長度為n,並且該單鏈表是環狀的,那麼第i次迭代時,p指向元素i mod n,q指向2i mod n。因此當i≡2i(mod n)時,p與q相遇。而i≡2i(mod n) => (2i - i) mod n = 0 => i mod n = 0 => 當i=n時,p與q相遇。這裡乙個簡單的理解是,p和q同時在操場跑步,其中q的速度是p的兩倍,當他們兩個同時出發時,p跑一圈到達起點,而q此時也剛 好跑完兩圈到達起點。

那麼當p與q起點不同呢?假定第i次迭代時p指向元素i mod n,q指向k+2i mod n,其中0(i+k) mod n = 0 => 當i=n-k時,p與q相遇。

這裡的關鍵是理解,其實,快指標和慢指標雖然一開始不在環裡,但是當他們都進入環裡的時候,其實這個問題的模型相當於兩個指標在環裡起點不同的模型。

懂了這點,後續很多證明都好理解了。

擴充套件閱讀:

推廣:1. 如果兩個指標的速度不一樣,比如p,q,( 0

sp(i) = pi

sq(i) = k + qi

如果兩個要相交於乙個節點,則 sp(i) = sq(i) =>  (pi) mod n = ( k+ qi ) mod n =>[ (q -p)i + k ]  mod n =0

=>  (q-p)i + k  = nn [n 為自然數]

=>  i = (nn -k) /(p-q)

i取自然數,則當 p,q滿足上面等式 即 存在乙個自然數n,可以滿足nn -k 是 p - q 的倍數時,保證兩者相交。

特例:如果q 是p 的步長的兩倍,都從同乙個起點開始,即 q = 2p , k =0, 那麼等式變為: nn=i: 即可以理解為,當第i次迭代時,i是圈的整數倍時,兩者都可以交,交點就是為起點。

2.如何判斷單鏈表的環的長度?

這個比較簡單,知道q 已經進入到環裡,儲存該位置。然後由該位置遍歷,當再次碰到該q 位置即可,所迭代的次數就是環的長度。

3. 如何找到鍊錶中第乙個在環裡的節點?

假設鍊錶長度是l,前半部分長度為k-1,那麼第乙個再環裡的節點是k,環的長度是 n, 那麼當q=2p時, 什麼時候第一次相交呢?當q指標走到第k個節點時,q指標已經在環的第 k mod n 的位置。即p和q 相差k個元素,從不同的起點開始,則相交的位置為 n-k, 則有了下面的圖:

從圖上可以明顯看到,當p從交點的位置(n-k) ,向前遍歷k個節點就到到達環的第乙個幾點,節點k.

演算法就很簡單: 乙個指標從p和q 中的第一次相交的位置起(n-k),另外乙個指標從煉表頭開始遍歷,其交點就是鍊錶中第乙個在環裡的交點。

下面是另外一種證明方法:

假設p和q分別以速度為v1和v2前進。如果有環,設指標p和q第一次進入環時,他們相對於環中第乙個節點的偏移位址分別為a和b(可以把偏移位址理解為節點個數)。如上圖。

這樣,可以看出,鍊錶有環的充要條件就是某一次迴圈時,指標p和q的值相等,就是它們相對環中首節點的偏移量相等。

我們設環中的結點個數為n,程式迴圈了m次。

由此可以有下面等式成立:(mod(n)即對n取餘)

(a+m*v1)mod(n) = (b+m*v2) mod(n)

設等式左邊mod(n)的最大整數為k1,等式右邊mod(n)的最大整數為k2,則

(a+m*v1)-k1*n = (b+m*v2)-k2*n

m= |((k2-k1)*n+a-b)/( v2-v1)|       ①

如果是等式①成立,就要使迴圈次數m為一整數。顯然如果v2-v1為1,則等式成立。

這樣p和q分別以速度為v1和v2且|v2-v1|為1時,按以上演算法就可找出鍊錶中是否有環。

2、對於問題2,記錄下問題1的碰撞點p,slow、fast從該點開始,再次碰撞所走過的運算元就是環的長度s。

3、問題3:有定理:碰撞點p到連線點的距離=頭指標到連線點的距離,因此,分別從碰撞點、頭指標開始走,相遇的那個點就是連線點。

4、問題3中已經求出連線點距離頭指標的長度,加上問題2中求出的環的長度,二者之和就是帶環單鏈表的長度

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

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

如何判斷鍊錶是否有環

背景 例如在乙個大的系統中,如果出現兩個鍊錶相交的情況,而且釋放其中乙個鍊錶所有的節點,那就會造成資訊的丟失,並且釋放其中乙個鍊錶的所有節點,那就會造成資訊的丟失並且與之相交的鍊錶也會受到影響,如下圖 給出兩個單鏈表的頭指標 h1,h2 假設兩個鍊錶均不帶環 方法一 判斷第乙個鍊錶所有的節點是否在第...

如何判斷鍊錶中是否有環

今天面試被問住了,很慚愧啊,回來上網查了一下思路。自己寫了點程式。1.如何判斷是否有環?如果有兩個頭結點指標,乙個走的快,乙個走的慢,那麼若干步以後,快的指標總會超過慢的指標一圈。2.如何計算環的長度?第一次相遇 超一圈 時開始計數,第二次相遇時停止計數。3.如何判斷環的入口點 碰撞點p到連線點的距...