链表题--难点

  1. 判断单链表是否带环?若带环,求环的长度?求环的入口点?
    判断是否带环:要判断链表有没有带环,不能按常理去判断最后一个节点的next是否为空,因为带环链表找不到最后一个节点。需借助快慢指针来解决。定义fast指针每次走两步,slow指针每次走一步,这样fast指针和slow指针如果在环里相遇,就可以断定有环,否则无环。
ListNode* Is_Loop_List(ListNode* pList)//是否带环,并返回相遇点
{
    if (pList == NULL)
    {
        return NULL;
    }
    ListNode* fast = pList;
    ListNode* slow = pList;
    while (fast->next && fast)
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
        {
            return slow;
        }
    }
    return NULL;
}
这里就出现了新问题:fast指针可以一次走三步,走四步……吗???
答案肯定是不能。因为fast每次走两步,slow每次走一步,快慢指针每次缩小的距离是一步,不会出现错过或者跳过的情况。而如果fast指针一次走三步,四步,会出现跳过的情况。

求环的长度:根据快慢指针相遇点,从相遇点的next开始遍历,当遇到相遇点停止,count进行计数,count值即为环的长度。

int Length_Loop(ListNode* pList)//求环的长度
{
    ListNode* meethead = Is_Loop_List(pList);
    while (meethead)
    {
        ListNode* prev = meethead->next;
        int count = 1;
        while (prev != meethead)
        {
            count++;
            prev = prev->next;
        }
        return count;
    }
    return 0;
}

求环的入口点:

这里写图片描述
上图可知:从环头节点和相遇点遍历节点,会在某个节点处相遇,这个节点就是环入口点。

ListNode* Enter_Node(ListNode* pList)//求环的入口点
{
    ListNode* meethead = Is_Loop_List(pList);
    while (meethead)
    {

        while (pList != meethead)
        {
            pList = pList->next;
            meethead = meethead->next;
        }
        return pList;
    }
    return NULL;
}

2.判断两个不带环链表是否相交,若相交,求交点。
先举例看一下何为相交链表

这里写图片描述
1>,先分别求出两个链表的长度,求出长度差;
2>,让长链表先走长度差的距离,接着短链表和长链表一起走;
3>,当出现节点数值一样时,那么相交点就找到了。

int Check_cross(ListNode* pList1, ListNode* pList2)//是否相交
{
    if (pList1 == NULL || pList2 == NULL)
    {
        return 0;
    }
    ListNode* prev1 = pList1;
    ListNode* prev2 = pList2;
    while(prev1->next)
    {
        prev1 = prev1->next;
    }
    while ( prev2->next)
    {
        prev2 = prev2->next;
    }
    if (prev1->data == prev2->data)
    {
        return 1;
    }
    return 0;
}

int Length_List(ListNode* pList)//求链表长度
{
    if (pList == NULL)
    {
        return 0;
    }
    int count = 1;
    while (pList->next)
    {
        count++;
        pList = pList->next;
    }
    return count;
}

ListNode* List_Intersection(ListNode* pList1, ListNode* pList2)//求链表的交点
{
    int Len1 = Length_List(pList1);
    int Len2 = Length_List(pList2);
    ListNode* longlist = pList1;
    ListNode* shortlist = pList2;
    if (Len1 < Len2)
    {
        longlist = pList2;
        shortlist = pList1;
    }
    int tmp = abs(Len1-Len2);
    while (tmp--)
    {
        longlist = longlist->next;
    }
    while (longlist)
    {
        if (longlist->data == shortlist->data) 
        {
            return longlist;
        }
        shortlist = shortlist->next;
        longlist = longlist->next;
    }
    return NULL;
}

3,判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
分为以下几种情况:

这里写图片描述

ListNode* List_loop_cross(ListNode* pList1, ListNode* pList2)
{
    if (pList1 == NULL || pList2 == NULL)
    {
        return NULL;
    }
    ListNode* enter1 = Enter_Node(pList1);//入口点
    ListNode* enter2 = Enter_Node(pList2);
    if (enter1 == NULL && enter2 == NULL)//两个链表的入口点为空,不带环 判断有无交点
    {
        return List_Intersection(pList1, pList2);
    }
    else if ((enter1 != NULL&&enter2 == NULL) || 
            (enter1 == NULL&&enter2 != NULL))//一个链表有环,一个链表无环,不相交
    {
        return NULL;
    }
    else if (enter1 == enter2)//入口点相等
    {
        enter1->next = NULL;
        enter2->next = NULL;//去掉环之后,按无环处理
        return List_Intersection(pList1, pList2);
    }
    else//一个环上有两个入口点
    {
        ListNode* cur = enter1->next;
        while (cur != enter1)
        {
            if (cur == enter2)
            {
                return cur;
            }
            cur = cur->next;
        }
        return NULL;
    }
}

4.求两个已排序单链表中相同的数据
1>,当两个节点数值相等时,尾插到新建链表上,并同时向后走一步;
2>,当两个数不相等时,数值小的节点向后走一步,数值大的节点不动,继续进行比较,直到任意链表为空。

ListNode* Union_Node(ListNode* List1, ListNode* List2)
{
    ListNode* newlist = NULL;
    ListNode* cur = List1;
    ListNode* prev = List2;
    while (cur && prev)
    {
        if (cur->data == prev->data)
        {
            PushBack(&newlist, cur->data);
            cur = cur->next;
            prev = prev->next;

        }
        else if (cur->data > prev->data)
        {
            prev = prev->next;
        }
        else
        {
            cur = cur->next;
        }
    }
    return newlist;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值