1. 程式人生 > >判斷單鏈表是否存在環及尋找環的入口點

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

再次 介紹 說明 != clas 頭部 開始 code 方法

一、判斷單鏈表是否存在環

這個問題有很多方法,最容易想到的就是記錄每個節點記錄的次數。這裏也介紹的是另一種簡單而常見的方法

快慢指針法:

定義兩個指針slow, fast。slow指針一次走1個結點,fast指針一次走2個結點。如果鏈表中有環,那麽慢指針一定會再某一個時刻追上快指針(slow == fast)。如果沒有環,則快指針會第一個走到NULL

 1 int has_cycle(node *head) {
 2     if (head == NULL)  return false;
 3     node* fast = head;
 4     node* slow = head;
5 6 while (1) 7 { 8 if (slow->next != NULL) slow = slow->next; //慢指針走一步 9 else return false; 10 if (fast->next != NULL && fast->next->next != NULL) fast = fast->next->next; //快指針走兩步 11 else return false; 12 13 if
(slow == fast) return true; 14 } 15 }

二、尋找環的入口點

其中一個回到起點:

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

證明:

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

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

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

  fast從頭開始走,步長為1.

  經過n步,fast和slow都會到達p + c這一點。將(2)-(1)得k*L = n,說明n是L的倍數,同時p + c = n,

  所以fast和slow都走p步時,fast距(p + c)差c,slow還差c回到(p + c),所以p是他們的第一個交點,之後的軌跡就一模一樣了。

 1 node* find_loopport(node * head)
 2 {
 3     node* fast = head;
 4     node* slow = head;
 5 
 6     //兩個互指不考慮
 7     //判斷是否存在環,如果存在得到相遇位置
 8     while (fast && fast->next)
 9     {
10         slow = slow->next;
11         fast = fast->next->next;
12         if (fast == slow)  break;
13     }
14     //fast到達NULL,表示不存在環
15     if (fast == NULL || fast->next == NULL)  return NULL;
16 
17     //將一個指針移到開始處,步長都變成一
18     fast = head;
19     while (slow != fast)
20     {
21         slow = slow->next;
22         fast = fast->next;
23     }
24     return  slow;
25 }

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