判断一个链表是否有环

如何判断一个单链表是否有环,若有环,找出环的入口?

下图是一个链表

设置两个链表指针fast, slow,初始值都指向链表头结点,然后两个指针都往后走,不同的是slow每次前进一步,即前进一个节点。fast每次前进两步,如果存在环,两个指针必定相遇。 

因为只有存在环的情况,我们才可能出现走的快的指针能再次遇到慢的指针。 
并且还有一点就是,若该链表存在环,则在慢指针还没走完一整个环的路程之前,两指针已经相遇。 
为什么?因为从慢指针进入环入口开始计时,慢指针走完一圈的时间,此时快指针已经走了两圈。所以在慢指针走完一圈之前,两指针一定会相遇。

把两指针相遇点记为O。则慢指针已走的环路程记为x,环剩下的路程记为y

设slow在相遇前走了s步,则fast走了2s步,设环长为r,有2s=s+nr,即s=nr。

由上图可知a+x=s, x+y=r,而我们的目标是找到a的位置。a+x=s=nr=(n-1)r+r=(n-1)r+y+x,则a=(n-1)r+y. 这个公式告诉我们,从链表头和相遇点O分别设一个指针,每次各走一步,这两个指针必定相遇,且相遇的第一个点为环入口点。

struct Link  
{  
    int data;  
    Link *next;  
};  
 
// 插入节点  
void insertNode(Link *&head, int data)  
{  
    Link *node = new Link;  
    node->data = data;  
    node->next = head;  
    head = node;  
}  
 
// 判断链表是否存在环  
Link* hasCycle(Link* head)  
{  
    Link *fast, *slow;  
    slow = fast = head;  
    while (fast && fast->next)  
    {  
        fast = fast->next->next;  
        slow = slow->next;  
        if (fast == slow)  
            return slow;  
    }  
    return NULL;  
}  
 
// 确定环的入口点,pos表示fast与slow相遇的位置  
Link* findCycleEntry(Link* head, Link* pos)  
{  
    while (head != pos)  
    {  
        head = head->next;  
        pos = pos->next;  
    }  
    return head;  

发布了60 篇原创文章 · 获赞 9 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_37876078/article/details/105584226