判斷單鏈表是否存在環及尋找環的入口點
阿新 • • 發佈:2018-09-09
再次 介紹 說明 != 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 }
判斷單鏈表是否存在環及尋找環的入口點