1.判断链表是否带环,带环返回1,不带换返回0
//判断链表是否带环,带环返回1,不带换返回0 int HasCycle(LinkNode* head) { if(head == NULL) { //空链表 return -1; } if(head->next == NULL) { return 0; } LinkNode* low = head; LinkNode* fast = head; while(fast != NULL && fast->next != NULL) { //快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环 low = low->next; fast = fast->next->next; if(low == fast) { //表示快慢指针相遇,链表带环,返回1 return 1; } } return 0; }
//测试函数 void TestHasCycle() { TITLE; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListPrint(head,"尾插4个元素,链表不带环"); int ret = HasCycle(head); printf("expect is 0,actual is %d\n",ret); LinkListPushBack(&head,'e'); LinkNode* D = LinkListFind(head,'d'); LinkNode* E = LinkListFind(head,'e'); LinkListPrint(head,"尾插一元素e并让e的next指向d,形成一个带环单链表"); E->next = D; ret = HasCycle(head); printf("expect is 1,actual is %d\n",ret); }
运行结果:
2.如果链表带环, 求出环的长度
解题思路:我们通过快慢指针相遇来判定出链表是否带环。如果得知带环,我们把两指针相遇位置记录下来,并再次遍历环,直达在此遇到相遇点。此时我们就可以得到环的长度。
//如果链表带环, 求出环的长度 size_t GetCycleLen(LinkNode* head) { if(head == NULL) { return 0; } if(head->next == NULL) { return 0; } LinkNode* low = head; LinkNode* fast = head; while(fast != NULL && fast->next != NULL) { //快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环 low = low->next; fast = fast->next->next; if(low == fast) { //表示快慢指针相遇,链表带环,此时跳出循环 //low指针指向的即为相遇点 break; } } LinkNode* cur = low->next; int i = 1; //遍历环一遍遇到相遇点结束,可得环的长度 while(cur != low) { i++; cur = cur->next; } return i; }
//测试函数 void TestGetCycleLen() { TITLE; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListPushBack(&head,'e'); LinkNode* D = LinkListFind(head,'d'); LinkNode* E = LinkListFind(head,'e'); LinkListPrint(head,"尾插5个元素,并让e的next指向d,形成一个带环单链表"); E->next = D; int ret = GetCycleLen(head); printf("expect is 2,actual is %d\n",ret); }
运行结果:
3.如果链表带环, 求出环的入口
解析:
//如果链表带环求出环的入口 LinkNode* GetCycleEntry(LinkNode* head) { if(head == NULL) { //空链表 return NULL; } if(head->next == NULL) { return 0; } LinkNode* low = head; LinkNode* fast = head; LinkNode* cur = head; LinkNode* meet = NULL; while(fast != NULL && fast->next != NULL) { //快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环 low = low->next; fast = fast->next->next; if(low == fast) { //表示快慢指针相遇,链表带环,记录相遇点.并跳出循环 meet = low; break; } } //当cur与相遇点的指针再次相遇时,即为环的入口点 while(cur != meet) { meet = meet->next; cur = cur->next; } return meet; }
测试函数:
void TestGetCycleEntry() { TITLE; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListPushBack(&head,'e'); LinkNode* D = LinkListFind(head,'d'); LinkNode* E = LinkListFind(head,'e'); LinkListPrint(head,"尾插5个元素,并让e的next指向d,形成一个带环单链表"); E->next = D; LinkNode* ret = GetCycleEntry(head); printf("expect is d,actual is %c\n",ret->data); }
运行结果: