判斷單鏈表是否存在環及尋找環的入口點

判斷鏈表是否存在環,有如下幾種解法:
1. 遍歷鏈表,將已經遍歷過的節點放在一個hash表中,如果一個節點已經存在hash表中,說明有環。時間:O(n) 空間:O(n)
2. 反轉鏈表。使用反轉鏈表的方法, 每過一個節點就把該節點的指針反向。若存在環,反轉next指針最終會走到鏈表頭部。若沒有環,反轉next指針會破壞鏈表結構(使鏈表反向), 所以爲還原鏈表,需要把鏈表再反向一次。 這種方法的空間複雜度是O(1), 實事上我們使用了3個額外指針;而時間複雜度是O(n), 我們最多2次遍歷整個鏈表(當鏈表中沒有環的時候)

3. 使用快慢指針



 尋找環的入口點: 當fast按照每次2步,slow每次一步的方式走,發現fast和slow重合,確定了單向鏈表有環路。接下來,讓fast回到鏈表的頭部,重新走,每次步長1,那麼當fast和slow再次相遇的時候,就是環路的入口了。

證明:在fast和slow第一次相遇的時候,假定slow走了n步,環路的入口是在p步,那麼

           slow走的路徑: p+c = n; c爲fast和slow相交點 距離環路入口的距離

           fast走的路徑: p+c+k*L = 2*n; L爲環路的周長,k是整數

          顯然,如果從p+c點開始,slow再走n步的話,還可以回到p+c這個點。

          同時,fast從頭開始走,步長爲1,經過n步,也會達到p+c這點。

          顯然,在這個過程中fast和slow只有前p步驟走的路徑不同。所以當p1和p2再次重合的時候,必然是在鏈表的環路入口點上。


slist * FindLoopPort(slist * head)
{
slist * slow = head, * fast = head;

while ( fast && fast -> next )
{
slow = slow -> next;
fast = fast -> next -> next;
if ( slow == fast ) break ;
}

if (fast == NULL || fast -> next == NULL)
return NULL;

slow = head;
while (slow != fast)
{
slow = slow -> next;
fast = fast -> next;
}



發佈了99 篇原創文章 · 獲贊 26 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章