带环链表相关问题

问题一:判断单链表是否带环?

这个问题比较容易解决,我们只需要使用快慢指针的方式便可以解决该问题,快指针(一次走两步)、慢指针一次走一步,如果链表带环这两个指针肯定会相遇,由于快指针走了两步,所以还是要考虑到节点个数是奇数还是偶数,所以【fast->next != NULL】也是要判断的!

//不带环返回NULL,带环返回相遇点
pNode CheckCycle(pList plist)
{
    pNode fast = plist;
    pNode slow = plist;
    if (plist == NULL)
        return NULL;
    while ((fast != NULL) && (((fast->next) != NULL)))
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
            return fast;
    }
    return NULL;
}

问题二:求链表的环的长度,参数为相遇点

从相遇点的下一个节点开始计数,直到重新回到相遇点即是换的长度!

//求环的长度,参数为相遇点
int GetCircleLength(pNode meet)
{

    pNode cur = NULL;
    int len = 1;

    assert(meet != NULL);
    assert(meet->next != NULL);

    cur = meet->next;

    while (cur != meet)
    {
        len++;
        cur = cur->next;
    }
    return len;
}

求入口点位置,参数为相遇点

这个相对前面两个来说比较难想,假设不带环的部分长度是x,从入口点到两个指针的相遇点的长度为y,环的长度为L,我们可以得到如图所示的公式
这里写图片描述
即慢指针走的步数乘以2就是快指针走的距离,我们可以得出x+y是个常数K*L(也就是k个环的长度),则x总是环的长度的倍数减去y,也就是说慢指针一个从链表的起始位置走,另一个慢指针从相遇点开始走,它们总会在入口点相遇!

//求入口点,参数为相遇点
pNode GetCycleEntryNode(pList list, pNode meetNode)
{
    pList cur = list;
    if (list == NULL)
        return NULL;
    if (meetNode == NULL)
        return NULL;

    while (cur != meetNode)
    {
        cur = cur->next;
        meetNode = meetNode->next;
    }
    return cur; 
}

测试代码

void test()
{
    int i = 0;
    pList plist = NULL;
    pNode pos = NULL;
    pNode entrance = NULL;
    InitList(&plist);
    for (i = 1; i <= 5; i++)
    {
        PushBack(&plist, i);
    }

    //带环
    Find(plist, 5)->next = Find(plist, 3);

    pos = CheckCycle(plist);
    if (pos != NULL){
        printf("带环,相遇点为 = %d\n", pos->data);
        printf("环的长度是:%d\n", GetCircleLength(pos));
        entrance = GetCycleEntryNode(plist, pos);
        printf("环的入口点是:%d\n", entrance->data);
    }
    else
    {
        printf("不带环\n");
    }
}

黎红丽,你一直都是我的女人

猜你喜欢

转载自blog.csdn.net/m0_38032942/article/details/81207320