實現一個算法,檢測單鏈表中是否有環,若是有環還要獲得環的入口。node
判斷是否有環:快慢指針法(也叫「龜兔賽跑」),慢指針每次移動一位,快指針每次移動兩位,若是有環,他們必定會相遇。算法
求環的入口:到達相遇的位置時,將塊指針移動到頭指針的位置,每次移動一位,二者再次相遇的位置就是環的入口。spa
爲何呢?.net
(先「借」一張圖指針
第一次相遇時,慢指針走 $x+k$,快指針走 $x+k+mr$($r$ 爲環的長度, $m \geq 1$),code
又由於快指針的速度是慢指針的兩倍,因此 $2(x+k) = x+k+mr$.blog
即 $x = mr-k$($m \geq 1$),get
慢指針已在 $k$ 處,塊指針置0,還過 $x$ 步,它們就會相遇於環的入口。it
#include <stdio.h> #include<stdbool.h> typedef struct node { int value; struct node *next; } node; bool ll_has_cycle(node *head) { if (head == NULL) return false; node* har = head; node* tor = head; while (1) { if (tor->next != NULL) tor = tor->next; else return false; if (har->next != NULL && har->next->next != NULL) har = har->next->next; else return false; if (tor == har) return true; } } int find_cycle_entrance(node *head) { if (head == NULL) return -1; node* har = head; node* tor = head; while (1) { if (tor->next != NULL) tor = tor->next; else return -1; if (har->next != NULL && har->next->next != NULL) har = har->next->next; else return -1; if (tor == har) { har = head; while(har != tor) { har = har->next; tor = tor->next; } return har->value; } } } void test_ll_has_cycle(void) { int i; node nodes[25]; //enough to run our tests for (i = 0; i < sizeof(nodes) / sizeof(node); i++) { nodes[i].next = 0; nodes[i].value = i; } nodes[0].next = &nodes[1]; nodes[1].next = &nodes[2]; nodes[2].next = &nodes[3]; printf("Checking first list for cycles. There should be none, ll_has_cycle says it has %s cycle\n", ll_has_cycle(&nodes[0]) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(&nodes[0])); nodes[4].next = &nodes[5]; nodes[5].next = &nodes[6]; nodes[6].next = &nodes[7]; nodes[7].next = &nodes[8]; nodes[8].next = &nodes[9]; nodes[9].next = &nodes[10]; nodes[10].next = &nodes[4]; printf("Checking second list for cycles. There should be a cycle, ll_has_cycle says it has %s cycle\n", ll_has_cycle(&nodes[4]) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(&nodes[4])); nodes[11].next = &nodes[12]; nodes[12].next = &nodes[13]; nodes[13].next = &nodes[14]; nodes[14].next = &nodes[15]; nodes[15].next = &nodes[16]; nodes[16].next = &nodes[17]; nodes[17].next = &nodes[14]; printf("Checking third list for cycles. There should be a cycle, ll_has_cycle says it has %s cycle\n", ll_has_cycle(&nodes[11]) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(&nodes[11])); nodes[18].next = &nodes[18]; printf("Checking fourth list for cycles. There should be a cycle, ll_has_cycle says it has %s cycle\n", ll_has_cycle(&nodes[18]) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(&nodes[18])); nodes[19].next = &nodes[20]; nodes[20].next = &nodes[21]; nodes[21].next = &nodes[22]; nodes[22].next = &nodes[23]; printf("Checking fifth list for cycles. There should be none, ll_has_cycle says it has %s cycle\n", ll_has_cycle(&nodes[19]) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(&nodes[19])); printf("Checking length-zero list for cycles. There should be none, ll_has_cycle says it has %s cycle\n", ll_has_cycle(NULL) ? "a" : "no"); printf("Entranc:%d\n", find_cycle_entrance(NULL)); } int main() { test_ll_has_cycle(); return 0; }