带环链表的处理

先给出几个要用的函数。

1.Begin():

Node* Begin(pNode pHead)
{
    return pHead;
}

2.End():

Node* End(pNode pHead)
{
    pNode pCur = pHead;
    if(!pCur)
    {
        return NULL;
    }
    while(pCur->_pNext)
    {
        pCur = pCur->_pNext;
    }
    return pCur;
}

3.Length():

size_t Length(pNode pHead)
{
    if(!pHead)
        return 0;
    size_t count = 0;
    while(pHead->_pNext)
    {
        count++;
        pHead = pHead->_pNext;
    }
    return count;
}

4.Print():

void print(pNode pHead)
{
    Node* pCur = pHead;
    while(pCur)
    {
        cout<<pCur->_or<<" ";
        pCur = pCur->_pNext;
    }
    cout<<endl;
}

5.删除无头单链表

(1)先将要删除结点(pCur)的下一个节点(pNext)值赋过去。
(2)将pCur的下一个节点连接到pNext的下一个节点,pCur->next = pNext->next。
(3)删除pNext即可。
先将pCur的值覆盖,再删除pCur的下一个节点。实际上释放的并不是pCur的空间。

void DeleteNotTaileNode(pNode pCur)
{
    pNode pNext = pCur->_pNext;
    pCur->_or = pNext->_or;
    pCur->_pNext = pNext->_pNext;
    free(pNext);
    pNext = NULL;
}

1.判断链表是否带环。
(1)定义两个指针fast和slow,fast每次走两个,slow每次走一个;
如果带环,fast总会与slow相遇, 返回相遇点。
如果不带环,那fast总会为空。

pNode IsCircle(pNode pHead)
{
    pNode fast = pHead;
    pNode slow = pHead;
    //如果不带环,那么fast一定会走到空。
    while(fast && fast->_pNext)
    {
        fast = fast->_pNext->_pNext;
        slow = slow->_pNext;
        if(fast == slow)
            return fast;
    }
    return NULL;
}

2.如果链表带环,求出环的长度。
如果链表带环,从相遇点走一圈,就能计算出len。

size_t GetCircleLen(pNode pMeetNode)
{
    pNode pNode = pMeetNode;
    size_t count = 1;
    while(pNode->_pNext != pMeetNode)
    {
        count++;
        pNode = pNode->_pNext;
    }
    return count;
}

3.如果带环,求出环的入口点。
这里写图片描述

pNode EnterCircleNode(pNode pHead, pNode pMeetNode)
{
    if(!pMeetNode)
        return NULL;
    pNode pFirst = pHead;
    pNode pSecond = pMeetNode;
    while(pFirst != pSecond)
    {
        pFirst = pFirst->_pNext;
        pSecond = pSecond->_pNext;
    }
    return pFirst;
}

4.判断两个不带环的链表是否相交。

bool IsIntersect(pNode pHead1, pNode pHead2)
{
    //两个链表相交,则最后一个节点一定相等。
    //所以只需判断最后一个节点是否相等即可。
    if(!pHead1 || !pHead2)
        return false;
    pNode pEndNode1 = End(pHead1);
    pNode pEndNode2 = End(pHead2);
    if(pEndNode1 == pEndNode2)
        return true;
    return false;
}

5.如果不带环的链表相交,则求出交点。
(1)计算链条链表的长度。
(2)让较长的链表先向下移动,直到两条链表长度相等。
(3)让两条链表同时向下移动,直到链表为空,判断链表是否相等。
若相等则返回该节点;
若不相等则返回NULL。

pNode IntersectNode(pNode pHead1, pNode pHead2)
{
    if(!IsIntersect(pHead1, pHead2))
        return NULL;
    size_t len1 = Length(pHead1);
    size_t len2 = Length(pHead2);
    pNode pCur1 = pHead1;
    pNode pCur2 = pHead2;
    int gas = len1 - len2;
    while(gas > 0)
    {
        //表明pHead1比pHead2长。
        pCur1 = pCur1->_pNext;
        gas--;
    }
    while(gas < 0)
    {
        //表明pHead2比pHead1长。
        pCur2 = pCur2->_pNext;
        gas++;
    }
    while(pCur1 && pCur2)
    {
        if(pCur1 == pCur2)
            return pCur1;
        pCur1 = pCur1->_pNext;
        pCur2 = pCur2->_pNext;
    }
    return NULL;
}

6.判断两个链表是否相交(可能带环)。

(1)判断两个链表是否带环,若不带环则调用上面函数进行处理;
若带环则进行下面步骤。
(2)获取到两个链表的相遇点 。
(3)让其中一个相遇点在环中移动,判断和另一个相遇点是否相等。若相等则两个带环链表相交,若不相等则不相交。

bool IsIntersectWithCircle(pNode pHead1, pNode pHead2)
{
    //两个链表相交,则最后一个节点一定相等。
    if(!pHead1 || !pHead2)
        return false;
    pNode pMeet1 = IsCircle(pHead1);
    pNode pMeet2 = IsCircle(pHead2);
    if(!pMeet1 && !pMeet2)
        return IsIntersect(pHead1, pHead2);
    while(pMeet1)
    {
        if(pMeet1 == pMeet2)
            return true;
        pMeet1 = pMeet1->_pNext;
    }
    return false;
}

7.判断两个链表的交点(可能带环)

这里写图片描述

pNode IntersectNodeWithCircle(pNode pHead1, pNode pHead2)
{
    //如果两个链表没有相交,则返回NULL;
    if(!IsIntersectWithCircle(pHead1, pHead2))
        return NULL;
    pNode pMeet1 = IsCircle(pHead1);
    pNode pMeet2 = IsCircle(pHead2);
    if(!pMeet1 && !pMeet2)
        return IntersectNode(pHead1, pHead2);
    //如果相交了,先判断入口点是否相同
    pNode EnterNode1 = EnterCircleNode(pHead1, pMeet1);
    pNode EnterNode2 = EnterCircleNode(pHead2, pMeet2);
    //入口点相同,为环外相交,存在一个交点
    //入口点不同,为环内相交,整个环都是交点
    if(EnterNode1 == EnterNode2)
    {
        //环内相交,将入口点与pHead2的头结点连起来,
        //重新形成一个带环链表,交点就是环的入口点.
        EnterNode1->_pNext = pHead2;
        pNode NewMeet = IsCircle(pHead1);
        pNode NewEnterNode = EnterCircleNode(pHead1, NewMeet);
        return NewEnterNode;
    }
    return NULL;
}

测试:

void FunTest()
{
    int arr1[]={1,18,6,72,9,43,27,0};
    int arr2[]={0,4,7};
    int i = 0;
    Node* pHead1;
    Init(&pHead1);
    //Node* pHead2;
    //Init(&pHead2);
    for(;i<sizeof(arr1)/sizeof(arr1[0]); i++)
    {
        Insert(&pHead1, arr1[i]);
    }
    print(pHead1);
    //DeleteNotTaileNode(Select(pHead1, 9));
    //print(pHead1);
    /*测试两个带环链表是否相交
    End(pHead1)->_pNext = Select(pHead1, 9);
    for(i=0;i<sizeof(arr2)/sizeof(arr2[0]); i++)
    {
        Insert(&pHead2, arr2[i]);
    }
    End(pHead2)->_pNext = Select(pHead1, 6);
    pNode Node = IntersectNodeWithCircle(pHead1, pHead2);
    */
    /*测试链表是否带环,和环的入口点
    End(pHead)->_pNext = Select(pHead, 9);
    pNode pMeetNode = IsCircle(pHead);
    int len = GetCircleLen(pMeetNode);
    pNode pEnter = EnterCircleNode(pHead, pMeetNode);
    */
    /*创建新链表
    Node* pHead2;
    Init(&pHead2);
    for(i=0;i<sizeof(arr2)/sizeof(arr2[0]); i++)
    {
        Insert(&pHead2, arr2[i]);
    }
    */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值