问题
实现一个算法,检测单链表中是否有环,如果有环还要得到环的入口。
分析
判断是否有环:快慢指针法(也叫“龟兔赛跑”),慢指针每次移动一位,快指针每次移动两位,如果有环,他们一定会相遇。
求环的入口:到达相遇的位置时,将块指针移动到头指针的位置,每次移动一位,两者再次相遇的位置就是环的入口。
为什么呢?
(先“借”一张图
第一次相遇时,慢指针走 $x+k$,快指针走 $x+k+mr$($r$ 为环的长度, $m geq 1$),
又因为快指针的速度是慢指针的两倍,所以 $2(x+k) = x+k+mr$.
即 $x = mr-k$($m geq 1$),
慢指针已在 $k$ 处,块指针置0,还过 $x$ 步,它们就会相遇于环的入口。
#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 ", ll_has_cycle(&nodes[0]) ? "a" : "no"); printf("Entranc:%d ", 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 ", ll_has_cycle(&nodes[4]) ? "a" : "no"); printf("Entranc:%d ", 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 ", ll_has_cycle(&nodes[11]) ? "a" : "no"); printf("Entranc:%d ", 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 ", ll_has_cycle(&nodes[18]) ? "a" : "no"); printf("Entranc:%d ", 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 ", ll_has_cycle(&nodes[19]) ? "a" : "no"); printf("Entranc:%d ", find_cycle_entrance(&nodes[19])); printf("Checking length-zero list for cycles. There should be none, ll_has_cycle says it has %s cycle ", ll_has_cycle(NULL) ? "a" : "no"); printf("Entranc:%d ", find_cycle_entrance(NULL)); } int main() { test_ll_has_cycle(); return 0; }
参考链接:https://blog.csdn.net/qq_36781505/article/details/91401474