链表相交带环问题+复杂链表的复制

一, 判断单链表是否带环?若带环,求环的长度?求环的入口点?
(1)判断是否带环:利用快慢指针法,快指针一次走两步,慢指针一次走一步,若快慢指针相遇,说明链表带环,并且返回相遇点即此时慢指针所指处,无环则返回NULL。

//判断是否带环
Node* IsHaveLoop(Node* head)
{
    if(head == NULL)
    {
        return NULL;
    }
    Node* fast = head;
    Node* slow = head;
    while(fast->next && fast)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast=slow)
        {
            return slow;
        }
    }
    return NULL;
}

(2)求环长:从相遇点出发,并开始计数,遍历一遍后再次回到相遇点,累加之数即为环地长度。

//求环长
int Lenloop(Node* head)
{
    Node* meet = IsHaveLoop(head);
    if(meet)
    {
        int count = 1;
        Node* tmp = meet->next;
        while(tmp!=meet)
        {
            tmp = tmp->next;
            count++;
        }
        return count;
    }
    return 0;
}

(3)求环的入口点:一个指针从链表头出发,一个指针从相遇点出发,两指针相遇处即为入口点。(这里可能不太好理解,后面我会图示举例讲解)

//求入口点
Node Enter(Node* head)
{
    Node* meet = IsHaveLoop(head);
    if(meet)
    {
        while(meet!=head)
        {
            meet = meet->next;
            head= head->next;
        }
        return head;
    }
    return NULL;
}

这里写图片描述
借助一个带环链表的实例:
这里写图片描述
二,初级版:判断两个链表是否相交,若相交,求交点。(假设链表不带环)
这种情况比较简单,首先遍历链表求得长度,计算长链表和短链表的差值Diflen,第二次遍历让较长的链表先走差值步,接着同时在两个链表上遍历,找到的第一个相同的节点就是两个链表的交点。
这里写图片描述

//求链表长度
int Getlen(Node* head)
{
    if(head == NULL)
    {
        return 0;
    }
    int count = 0;
    Node* tmp = head;
    while(tmp->next)
    {
        count++;
        tmp = tmp->next;
    }
    return count;
}
//判断链表是否相交并求交点
Node* IsInter1(Node* head1, Node* head2)
{
    int len1 = Getlen(head1);
    int len2 = Getlen(head2);
    int Diflen = len1-len2;
    Node* long = head1;
    Node* short = head2;
    if(len1<len2)
    {
        long = head2;
        short = head1;
    }
    forint i = 0;i<Diflen;++i)
    {
        long = long->next;//快指针先走相差的步数
    }
    whilelong)
    {
        long = long->next;//快慢指针一起走
        short = short->next;
        if(long == short)
        {
            return long;
        }
    }
    return NULL;
}

三,升级版:判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
这种情况比较复杂,分类进行分析:

Node* IsInter2(Node* head1,Node* head2)
{
    if((head1=NULL)||(head2=NULL)
    {
        return NULL;
    }
    Node* enter1 = Enter(head1);
    Node* enter2 = Enter(head2);

    //1情景:两个链表都不带环,转换为上面问题求解
    if((enter1 == NULL)&&(enter2 == NULL)
    {
        return IsInter1(head1,head2);
    }
    //2情景:一个带环一个不带环且不相交
    else if((enter1 == NULL)&&(enter2 != NULL)||(enter1 != NULL)&&(enter2 == NULL)
    {
        return NULL;
    }
    //3情景:在环的入口点前面相交,去掉环转换成无环问题
    else if(enter1 == enter2)
    {
        enter1->next = NULL;//去掉环
        enter2->next = NULL;
        return IsInter1(head1,head2);
    }
    //4情景:同环,两个入口点
    else 
    {
        Node* tmp = enter1->next;
        while(tmp != enter)
        {
            if(tmp = enter2)
            {
                return enter1;
            }
            tmp = tmp->next;
        }
        return NULL;
    }
}

这里写图片描述
四,复杂链表的复制
实现ComplexListNode*Clone(ComplexListNode* head),复制一个复杂链表。在复杂链表中,每个节点除了有一个next指针指向下一个节点,还有一个sibling指针指向链表中的任意节点。
原始链表如图:
这里写图片描述
节点定义:

struct ComplexListNode
{
    int data;
    ComplexListNode* next;
    ComplexListNode* sibling;
};

第一步:复制原始链表的任意节点X并创建*X,再把每一个*X连接到对应的X后面。

这里写图片描述

void CloneNode(ComplexListNode* head)//复制链表节点
{
    if(head == NULL)
    {
        return NULL;
    }
    ComplexListNode* cur = head;
    ComplexListNode* cloned;
    while(cur != NULL)
    {
        cloned = new ComplexListNode(cur->data);
        cur->next = cloned;
        cloned->next = cur->next;
        cur = cloned->next;
    }
}

第二步:设置复制出来的节点的sibling。假设原始链表上的X的sibling指向节点Y,复制节点对应的sibling指向节点Y的next节点*Y。

这里写图片描述

void Clonesibling(ComplexListNode* head)//设置复制节点的sibling

{
    ComplexListNode* cur = head;
    ComplexListNode* cloned;
    while(cur!=NULL)
    {
        cloned = cur->next;
        if(cur->sibling != NULL)
        {
            cloned->sibling = cur->sibling->next;
        }
        cur = cloned ->next;
    }
}

第三步:把长链表拆分成两个链表。奇数位置的节点链接起来就是原始链表,偶数位置的节点链接起来就是复制出来的链表。
这里写图片描述

ComplexListNode* ReconNode(ComplexListNode* head)
{
    ComplexListNode* cur = head;
    ComplexListNode* clonedhead = NULL;
    ComplexListNode* clonedcur = NULL;

    if(cur != NULL)//连接奇数节点也就是原始节点
    {
        clonedhead = clonedcur = cur->next;
        cur->next = clonedcur -> next;
        cur = cur -> next;
    }
    while(cur!=NULL)
    {
        clonedcur->next = cur->next;//连接偶数节点也就是复制节点
        clonedcur = clonedcur->next;
        cur->next = clonedcur->next;
        cur = cur->next;
    }
    return clonedhead;
}

最后把上面三步整合起来就是复制复杂链表的过程。

ComplexListNode* Clone(ComplexListNode* head)
{
    CloneNode(head);
    Clonesibling(head);
    return ReconNode(head);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值