給定乙個單鏈表,只給出頭指標h:
1、如何判斷是否存在環?
2、如何知道環的長度?
3、如何找出環的連線點在**?
4、帶環鍊錶的長度是多少?
解法:
1、對於問題1,使用追趕的方法,設定兩個指標slow、fast,從頭指標開始,每次分別前進1步、2步。如存在環,則兩者相遇;如不存在環,fast遇到null退出。
2、對於問題2,記錄下問題1的碰撞點p,slow、fast從該點開始,再次碰撞所走過的運算元就是環的長度s。
3、問題3:有定理:碰撞點p到連線點的距離=頭指標到連線點的距離,因此,分別從碰撞點、頭指標開始走,相遇的那個點就是連線點。(證明在後面附註)
4、問題3中已經求出連線點距離頭指標的長度,加上問題2中求出的環的長度,二者之和就是帶環單鏈表的長度
判斷是否存在環的程式:
bool i***itsloop(slist *head)
return !(fast == null || fast->next == null);
}
尋找環連線點(入口點)的程式:
slist* findloopport(slist *head)
if (fast == null || fast->next == null)
return null;
slow = head;
while (slow != fast)
return slow;
}
附註
問題3的證明如下:
鍊錶形狀類似數字 6 。
假設甩尾(在環外)長度為 a(結點個數),環內長度為 b 。
則總長度(也是總結點數)為 a+b 。
從頭開始,0 base 編號。
將第 i 步訪問的結點用 s(i) 表示。i = 0, 1 ...
當 i<a 時,s(i)=i ;
當 i≥a 時,s(i)=a+(i-a)%b 。
分析追趕過程:
兩個指標分別前進,假定經過 x 步後,碰撞。則有:s(x)=s(2x)
由環的週期性有:2x=tb+x 。得到 x=tb 。
另,碰撞時,必須在環內,不可能在甩尾段,有 x>=a 。
連線點為從起點走 a 步,即 s(a)。
s(a) = s(tb+a) = s(x+a)。
得到結論:從碰撞點 x 前進 a 步即為連線點。
根據假設易知 s(a-1) 在甩尾段,s(a) 在環上,而s(x+a) 必然在環上。所以可以發生碰撞。
而,同為前進 a 步,同為連線點,所以必然發生碰撞。
綜上,從 x點和從起點同步前進,第乙個碰撞點就是連線點。
假設單鏈表的總長度為l,頭結點到環入口的距離為a,環入口到快慢指標相遇的結點距離為x,環的長度為r,慢指標總共走了s步,則快指標走了2s步。另外,快指標要追上慢指標的話快指標至少要在環裡面轉了一圈多(假設轉了n圈加x的距離),得到以下關係:
s = a + x;
2s = a + nr + x;
=>a + x = nr;
=>a = nr - x;
由上式可知:若在頭結點和相遇結點分別設一指標,同步(單步)前進,則最後一定相遇在環入口結點,搞掂!
附圖:
判斷乙個單鏈表是否有環及環
判斷乙個單鏈表是否有環及環的鏈結點 蒙恩的罪人 給定乙個單鏈表,只給出頭指標h 1 如何判斷是否存在環?2 如何知道環的長度?3 如何找出環的連線點在 4 帶環鍊錶的長度是多少?解法 1 對於問題1,使用追趕的方法,設定兩個指標slow fast,從頭指標開始,每次分別前進1步 2步。如存在環,則兩...
判斷乙個單鏈表是否有環及環入口
要求 不允許修改鍊錶結構 時間複雜度o n 空間複雜度o 1 判斷是否有環 如果鍊錶有環,那麼在遍歷時則會陷入死迴圈。使用快慢指標 快指標移動2步,慢指標移動1步 如果走到某一步,快慢指標相遇,則說明有環 環入口點 我們假設鍊錶頭部到環入口距離 len,環入口到快慢指標交匯點的距離為x,環的長度為r...
判斷乙個單鏈表是否有環
一 判斷鍊錶是否存在環 設定兩個指標 fast,slow 初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入 環,而slow後進入環,兩個指標必定相遇。當然,fast先行頭到尾部為null,則為無環鏈表 程式如下 bool i itsloop listn...