判断两个单链表是否相交(链表中可能有环的情况下)

原文链接:http://www.cppblog.com/zengwei0771/articles/172700.html

题目描述:判断两个单链表是否相交,如果相交,给出相交的第一个点(链表中可能有环的情况下)

这里是①判断单链表是否有环,并求出环的入口点;②判断两个链表是否相交(链表中无环),并求出相交节点 的文章
 
http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html

分析:
①:判断链表1是否有环,并记录其长度L1,尾节点b1(无环),环入口点a1(有环)
②:判断链表2是否有环,并记录其长度L2,尾节点b2(无环),环入口点a2(有环)
③:若一个有环,另一个没环,则判断不相交,结束
④:若两个都没环,则两个尾节点一点是一样的,所以比较两个尾节点是否相同。若不相同则判断不相交,结束;若相同,则到⑥。
⑤:若两个都有环,有如下图三种情况:a1与a2不相等,且不在一个环中,则不相交,结束;a1等于a2,跳到⑥;a1与a2不相等,但在一个环中,对于链表1来说a1是它的相交首节点,对于链表2来说a2是它的相交首节点。 















⑥:对于两个链表重头开始遍历,长链表节点先出发前进(Max(L1,L2)-Min(L1,L2))步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点

代码如下:

typedef struct Node
  {
      int value;
      Node* pNext;
  }* List;
  
  Node* IsListCross(List L1, List L2)
  {
      if (L1 == NULL || L2 == NULL)
     {
         return NULL;
     }
 
     int len1 = 0;                //L1的长度
     int len2 = 0;                //L2的长度
     bool L1HasLoop = false;        //L1是否有环
     bool L2HasLoop = false;        //L2是否有环
     Node *crossEntry1 = NULL, *crossEntry2 = NULL, *end1 = NULL, *end2 = NULL;
     Node *pNode1, *pNode2, *pNode3;    //临时节点指针
 
     //①
     pNode1 = L1;
     pNode2 = L1;
     while (pNode2 && pNode2->pNext)
     {
         len1++;
         pNode1 = pNode1->pNext;
         pNode2 = pNode2->pNext->pNext;
         if (pNode1 == pNode2)
         {
             L1HasLoop = true;
             break;
         }
     }
     if (L1HasLoop)
     {
         pNode2 = L1;
         while (pNode1 != pNode2)
         {
             len1++;
             pNode1 = pNode1->pNext;
             pNode2 = pNode2->pNext;
         }
         crossEntry1 = pNode1;
     }
     else
     {
         pNode3 = pNode1;
         while (pNode3->pNext)
         {
             len1++;
             pNode3 = pNode3->pNext;
         }
         end1 = pNode3;
         len1++;
     }
 
     //②
     pNode1 = L2;
    pNode2 = L2;
     while (pNode2 && pNode2->pNext)
     {
         len2++;
         pNode1 = pNode1->pNext;
         pNode2 = pNode2->pNext->pNext;
         if (pNode1 == pNode2)
         {
             L2HasLoop = true;
             break;
         }
     }
     if (L2HasLoop)
     {
         pNode2 = L2;
         while (pNode1 != pNode2)
         {
             len2++;
             pNode1 = pNode1->pNext;
             pNode2 = pNode2->pNext;
         }
         crossEntry2 = pNode1;
     }
     else
     {
         pNode3 = pNode1;
         while (pNode3->pNext)
         {
             len2++;
            pNode3 = pNode3->pNext;
         }
         end2 = pNode3;
         len2++;
     }
 
     //③
     if (L1HasLoop != L2HasLoop)
     {
         return NULL;
     }
    //④
    else if (L1HasLoop == false)
    {
        if (end1 != end2)
        {
            return NULL;
        }
    }
    //⑤
    else
    {
        //a1 != a2
        if (crossEntry1 != crossEntry2)
        {
            bool onOneLoop = false;
            pNode1 = crossEntry1->pNext;
            while (crossEntry1 != pNode1)
            {
                if (pNode1 == crossEntry2)
                {
                    onOneLoop = true;
                    break;
                }
                pNode1 = pNode1->pNext;
            }
            //a1 != a2,且不在一个环中
            if (!onOneLoop)
            {
                return NULL;
            }
            //a1 != a2,在一个环中
            else
            {
                return crossEntry1;
            }
        }
    }
    //⑥
    pNode1 = L1;
    pNode2 = L2;
    int gap;
    if (len1 > len2)
    {
        gap = len1 - len2;
        while (gap)
        {
            pNode1 = pNode1->pNext;
            gap--;
        }
    }
    else
    {
        gap = len2 - len1;
        while (gap)
        {
            pNode2 = pNode2->pNext;
            gap--;
        }
    }
    while (pNode1 != pNode2)
    {
        pNode1 = pNode1->pNext;
        pNode2 = pNode2->pNext;
    }
    return pNode1;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值