單鏈表有環的定義:鏈表的尾節點指向了鏈接中間的某個節點。
如下圖所示,如果有環,則遍歷到結點7時,又重新回到結點3,結點3就是環的入口結點。
思路:采用快慢指針的思想,設兩個工作指針,一個快一個慢,如果鏈表有環,它們必然會在某個結點處相遇。
功能函數:
/* 判斷鏈表是否有環 */ int hasLoop(Node *head) { Node *p1,*p2; if(head == NULL || head->next == NULL) //鏈表為空,或是單結點鏈表直接返回頭結點 return 0; p1 = p2 = head; while(p1->next != NULL && p1->next->next != NULL) { p1 = p1->next->next; p2 = p2->next; if(p1 == p2) return 1; } return 0; }
這里需要注意一個問題,為什么快慢指針相遇就說明鏈表有環呢?該如何分析??
(以下內容來自:http://www.cnblogs.com/youxin/p/3303172.html)
1.鏈表中是否有環的判斷
可以設置兩個指針(fast,slow),初始值均指向頭,slow每次向前一步,fast每次向前兩步;
如果鏈表中有環,則fast先進入環中,而slow后進入環中,兩個指針在環中必定相遇;
如果fast遍歷到尾部為NULL,則無環
2.鏈表有環,判斷環的入口點
當fast若與slow相遇時,slow肯定沒有走遍歷完鏈表,而fast已經在環內循環了n圈(1<=n)。假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長為r,則:
2s = s + nr
s= nr
設整個鏈表長L,入口環與相遇點距離為x,起點到環入口點的距離為a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)為相遇點到環入口點的距離,由此可知,從鏈表頭到環入口點等於(n-1)循環內環+相遇點到環入口點
(L-a-x為相遇點到環入口點的距離,怎么理解,比如上面的,我們假設slow和fast在點3相遇,
啟動為1,環入口點 為2,相遇點為3,走了(L-a-x)長的距離后就回到了2點。
我們在起點和環相遇點各設置一個指針,每次各走一步,必定相遇。相遇一定在2點,為什么,
)
因而,可以在鏈表頭,相遇點分別設定一個指針,每次各走一步,兩個指針必定相遇,則相遇第一點為環入口點。