關於鏈表是否有環,其實是一系列問題,主要包括以下幾個:
1.判斷單鏈表是否有環:
使用快慢指針fast和slow,fast每次走兩步,slow每次走一步,如果有環,肯定會相遇,如果沒有,則指針fast遇到NULL退出。追及相遇問題。
2.求有環單鏈表的環長
在環上相遇后,記錄第一次相遇點為Pos,之后指針slow繼續每次走1步,fast每次走2步。在下次相遇的時候fast比slow正好又多走了一圈,也就是多走的距離等於環長。
設從第一次相遇到第二次相遇,設slow走了len步,則fast走了2*len步,相遇時多走了一圈:
環長=2*len-len
3.求有環單鏈表的環連接點位置
第一次碰撞點Pos到連接點Join的距離=頭指針到連接點Join的距離,因此,分別從第一次碰撞點Pos、頭指針head開始走,相遇的那個點就是連接點。在環上相遇后,記錄第一次相遇點為Pos,連接點為Join,假設頭結點到連接點的長度為LenA,連接點到第一次相遇點的長度為x,環長為R。
第一次相遇時,slow走的長度 S = LenA + x;
第一次相遇時,fast走的長度 2S = LenA + n*R + x;
所以可以知道,LenA + x = n*R; LenA = n*R -x;
4.求有環單鏈表的鏈表長
上述2中求出了環的長度;3中求出了連接點的位置,就可以求出頭結點到連接點的長度。兩者相加就是鏈表的長度。
5.如果快指針每次走三步,四步,五步...會怎么樣?
不管快指針走多少步,只要有環就會與慢指針相遇,因為慢指針每次都走一步。但是如果快指針每次走三步以上,就會導致上述公式不成立。比如說快指針每次走三步,則公式變為:
第一次相遇時,slow走的長度 S = LenA + x;
第一次相遇時,fast走的長度 3*S = LenA + n*R + x;
所以可以知道,2*LenA + 2*x = n*R; LenA = n*R/2 -x;
舉例:頭結點之后就是環的入口,環除了入口還有一個節點,fast每次走三步,slow每次走一步,第一次會在環的入口相遇,分別從第一次碰撞點Pos、頭指針head開始走,無法相遇。
參考文獻:
https://www.cnblogs.com/xudong-bupt/p/3667729.html