、什么是环:
环:是链表里面出现指向自己或者指向这个结点前面的元素,从而使链表形成一个闭环的状态。
2、如何判断链表是否含有环
方法1(最优解):快慢指针:
思路:设置两个指针p、q,开始都在头结点,但是p走一步,q走两步。这样子,如果是没有环的链表,p,q是不可能相遇的
但是如果链表里面含有环,则他们一定会相遇
代码实现
3、求环的入口
有了上面的知识,现在我们可以考虑一个新的问题,将环的入口求出来如上图,环的入口为3,那么我们怎么通过代码求出来呢?
思路:同样,我们需要判断该链表是否为带环链表,使用快慢指针的方法。当两个指针相遇,即证明有环,此时:将p返回头节点,q留在相遇的结点,p,q再分别一步一步的进行遍历,当p,q再次相遇,则该节点必定为环的入口。
代码实现
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead )
{
struct ListNode*p = pHead;
struct ListNode*q = pHead;
if(pHead == NULL)
{
return NULL;
}
while(p != NULL&&p->next!=NULL)
{
p = p->next->next;
q = q->next;
if(q == p)//有环
{
p = pHead;
while(q != p )//以相遇为条件进行循环遍历
{
p = p->next;
q = q->next;
}
return p;
}
}
return NULL;
}
也有一种取巧的方法
利用了C新建地址的特性
C malloc 的地址总是大于所有已有的地址
所以假如下一个地址小于上一个,
那必是之前经过的节点。
struct ListNode *detectCycle(struct ListNode *head) {
for(;head;head=head->next)
if ((head->next)<=head) return head->next;
return NULL;
}