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);
}
运行结果: