《C语言实现链表相交、带环问题》

例题:

//1.判断单链表是否带环?若带环,求环的长度?求环的入口点?
//2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
//3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
//4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,
//还有一个random指针指向这个链表中的一个随机节点或者NULL,
//现在要求实现复制这个链表,返回复制后的新链表。
////ps: 复杂链表的结构 
//struct ComplexNode
//{
//  int _data; // 数据 
//  struct ComplexNode * _next; // 指向下一个节点的指针 
//  struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空) 
//};

基本函数:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<math.h>

typedef int DataType;//节点中数据类型

typedef struct ListNode//节点数据结构
{
    DataType data;
    struct ListNode *next;
} ListNode;


ListNode *Find(ListNode *plist,DataType x)//查找函数,返回查找到节点的地址
{
    ListNode *cur = plist;
    while (cur)
    {
        if ((cur->data) == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return cur;
}


ListNode *BuyNode(DataType x)//产生一个节点并把节点中的数据置数,返回节点地址
{
    ListNode *plist = (ListNode *)malloc(sizeof(ListNode));
    if (plist != NULL)
    {
        plist->data = x;
        plist->next = NULL;
        return plist;
    }
    return NULL;
}



void PrintList(ListNode *plist)//打印单链表
{
    assert(plist != NULL);
    while (plist)
    {
        printf("%d->",plist->data);
        plist = plist->next;
    }
    printf("NULL\n");
}

void PushBuck(ListNode **pplist,DataType x)//在函数尾部插入节点
{
    ListNode *cur = NULL;
    assert(pplist);
    cur = *pplist;
    if (*pplist == NULL)
    {
        *pplist = BuyNode(x);
        return;
    }
    while ((cur->next) != NULL)
    {
        cur = cur->next;
    }
    cur->next = BuyNode(x);
}

1.判断单链表是否带环?若带环,求环的长度?求环的入口点?

思路:
这里写图片描述

ListNode *IsCycle(ListNode *plist)//判断是否带环
{
    ListNode *fast = plist;
    ListNode *slow = plist;
    assert(plist);
    while ((fast != NULL) && (fast->next != NULL))
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
            return fast;
    }
    return NULL;
}

int GetCycleLen(ListNode *meetnode)//求环的长度
{
    ListNode *cur = NULL;
    int count = 1;
    assert(meetnode);
    cur = meetnode->next;
    while (cur != meetnode)
    {
        cur = cur->next;
        count++;
    }
    return count;
}

ListNode *GetCycleEnter(ListNode *plist, ListNode *meetnode)//求环的入口点
{
    assert(plist);
    assert(meetnode);
    while (plist != meetnode)
    {
        plist = plist->next;
        meetnode = meetnode->next;
    }
    return plist;
}

void Test()
{
    ListNode *plist = NULL;
    ListNode *tmp1 = NULL;
    ListNode *tmp2 = NULL;
    ListNode *tmp = NULL;
    PushBuck(&plist, 1);
    PushBuck(&plist, 2);
    PushBuck(&plist, 3);
    PushBuck(&plist, 4);
    PushBuck(&plist, 5);
    PushBuck(&plist, 6);
    PushBuck(&plist, 7);


    tmp1 = Find(plist, 3);
    tmp2 = Find(plist, 7);
    tmp2->next = tmp1;
    tmp = IsCycle(plist);
    if (tmp == NULL)
        printf("不带环!\n");
    else
    {
        printf("带环!\n");
        printf("环的长度为:%d\n",GetCycleLen(tmp));
        printf("环的入口点为:%d\n",GetCycleEnter(plist,tmp)->data);
    }
}

结果:
这里写图片描述


2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
bool CheckIsMeet(ListNode *plist1,ListNode *plist2)//判断是否相交
{
    assert(plist1);
    assert(plist2);
    while (plist1->next != NULL)
    {
        plist1 = plist1->next;
    }
    while (plist2->next != NULL)
    {
        plist2 = plist2->next;
    }
    if (plist1 == plist2)
    {
        return true;
    }
    else
    {
        return false;
    }
}

ListNode *AnswerMeetNode(ListNode *plist1,ListNode *plist2)//若相交,求交点
{
    int count1 = 0;
    int count2 = 0;
    int count = 0;
    ListNode *cur1 = plist1;
    ListNode *cur2 = plist2;
    while (cur1 != NULL)
    {
        count1++;
        cur1 = cur1->next;
    }
    while (cur2 != NULL)
    {
        count2++;
        cur2 = cur2->next;
    }
    count = count1 - count2;
    if (count > 0)
    {
        while (count--)
        {
            plist1 = plist1->next;
        }
    }
    else
    {
        count = -count;
        while (count--)
        {
            plist2 = plist2->next;
        }
    }
    while (plist1 != plist2)
    {
        plist1 = plist1->next;
        plist2 = plist2->next;
    }
    return plist1;
}

void Test1()
{
    ListNode *plist1 = NULL;
    ListNode *plist2 = NULL;
    ListNode *tmp1 = NULL;
    ListNode *tmp2 = NULL;
    bool flag = true;
    PushBuck(&plist1, 1);
    PushBuck(&plist1, 3);
    PushBuck(&plist1, 5);
    PushBuck(&plist1, 7);
    PushBuck(&plist1, 8);
    PushBuck(&plist1, 9);
    PushBuck(&plist1, 10);

    PushBuck(&plist2, 2);
    PushBuck(&plist2, 4);
    PushBuck(&plist2, 6);

    tmp1 = Find(plist2, 6);
    tmp2 = Find(plist1, 7);
    tmp1->next = tmp2;
    flag = CheckIsMeet(plist1, plist2);
    if (flag)
    {
        printf("相交!\n");
        printf("交点为:%d\n",AnswerMeetNode(plist1,plist2)->data);
    }
    else
    {
        printf("不想交!\n");
    }
}

结果:
这里写图片描述


3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

思路:
这里写图片描述

RetuenNoode CheckIsMeetTop(ListNode *plist1, ListNode *plist2)//判断两个链表是否相交,若相交,求交点.(假设链表可能带环)【升级版】
{
    ListNode *tmp1 = NULL;
    ListNode *tmp2 = NULL;
    RetuenNoode ret = { 0, NULL, NULL };
    assert(plist1);
    assert(plist2);
    tmp1 = IsCycle(plist1);
    tmp2 = IsCycle(plist2);
    if ((tmp1 == NULL) && (tmp2 == NULL))
    {
        //都不带环
        tmp1 = plist1;
        tmp2 = plist2;
        while (tmp1->next != NULL)
        {
            tmp1 = tmp1->next;
        }
        while (tmp2->next != NULL)
        {
            tmp2 = tmp2->next;
        }
        if (tmp1 == tmp2)
        {
            //相交
            ret.plist1 = AnswerMeetNode(plist1, plist2);
            ret.flag = 1;
            return ret;
        }
        else
        {
            //不相交
            ret.flag = 1;
            return ret;
        }
    }
    else if ((tmp1 != NULL) && (tmp2 != NULL))
    {
        //两者都带环
        ListNode *tmp = tmp1->next;
        while ((tmp != tmp2) && (tmp != tmp1))
        {
            tmp = tmp->next;
        }
        if (tmp == tmp2)
        {
            //相交
            tmp1 = GetCycleEnter(plist1,tmp1);
            tmp2 = GetCycleEnter(plist2,tmp2);
            if (tmp1 == tmp2)
            {
                //交点在链上
                int count1 = 0;
                int count2 = 0;
                int count = 0;
                ListNode *cur1 = plist1;
                ListNode *cur2 = plist2;
                while (cur1 != tmp1)
                {
                    count1++;
                    cur1 = cur1->next;
                }
                while (cur2 != tmp1)
                {
                    count2++;
                    cur2 = cur2->next;
                }
                count = count1 - count2;
                if (count > 0)
                {
                    while (count--)
                    {
                        plist1 = plist1->next;
                    }
                }
                else
                {
                    count = -count;
                    while (count--)
                    {
                        plist2 = plist2->next;
                    }
                }
                while (plist1 != plist2)
                {
                    plist1 = plist1->next;
                    plist2 = plist2->next;
                }
                ret.plist1 = plist1;
                ret.flag = 3;
                return ret;
            }
            else
            {
                //两个交点都在环上
                ret.plist1 = tmp1;
                ret.plist2 = tmp2;
                ret.flag = 3;
                return ret;
            }
        }
        else
        {
            //不相交
            ret.flag = 3;
            return ret;
        }
    }
    else
    {
        //一个带环,一个不带环。必不相交
        ret.flag = 2;
        return ret;
    }
}


void Test2()
{
    RetuenNoode ret = {0,NULL,NULL};
    ListNode *plist1 = NULL;
    ListNode *plist2 = NULL;
    ListNode *tmp1 = NULL;
    ListNode *tmp2 = NULL;
    PushBuck(&plist1, 1);
    PushBuck(&plist1, 3);
    PushBuck(&plist1, 5);
    PushBuck(&plist1, 7);
    PushBuck(&plist1, 8);
    PushBuck(&plist1, 9);
    PushBuck(&plist1, 10);

    PushBuck(&plist2, 0);
    PushBuck(&plist2, 2);
    PushBuck(&plist2, 4);
    PushBuck(&plist2, 6);

    tmp1 = Find(plist1, 10);//第三类相交 b> 2>
    tmp2 = Find(plist1, 7);
    tmp1->next = tmp2;
    tmp1 = Find(plist1, 9);
    tmp2 = Find(plist2, 6);
    tmp2->next = tmp1;

    //tmp1 = Find(plist1, 10);//第三类相交 b> 1>
    //tmp2 = Find(plist1, 7);
    //tmp1->next = tmp2;
    //tmp1 = Find(plist1, 5);
    //tmp2 = Find(plist2, 6);
    //tmp2->next = tmp1;

    //tmp1 = Find(plist2, 2);//第三类不相交
    //tmp2 = Find(plist2, 6);
    //tmp2->next = tmp1;
    //tmp1 = Find(plist1, 7);
    //tmp2 = Find(plist1, 10);
    //tmp2->next = tmp1;

    //tmp1 = Find(plist1, 7);//第二类不相交
    //tmp2 = Find(plist1, 10);
    //tmp2->next = tmp1;

    //第一类不相交

    //tmp1 = Find(plist2, 6);//第一类相交
    //tmp2 = Find(plist1, 7);
    //tmp1->next = tmp2;

    ret = CheckIsMeetTop(plist1,plist2);
    if (ret.flag == 3)
    {
        if ((ret.plist1) && (ret.plist2))
        {
            printf(" 第三类 -> b> -> 2> :\nMeetNode1:%d\nMeetNode2:%d\n", ret.plist1->data, ret.plist2->data);
        }
        else if (ret.plist1)
        {
            printf("第三类 -> b> -> 1> :\nMeetNode:%d\n", ret.plist1->data);
        }
        else
        {
            printf("第三类不相交!\n");
        }
    }
    else if (ret.flag == 1)
    {
        if (ret.plist1)
        {
            printf("第一类相交:\nMeetNode:%d\n", ret.plist1->data);
        }
        else
        {
            printf("第一类不相交!\n");
        }
    }
    else
    {
        printf("第二类不相交!\n");
    }
}

int main()
{
    //Test();
    //Test1();
    Test2();
    return 0;
}

结果:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述


4.复杂链表的复制。

思路:
这里写图片描述

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

typedef struct ComplexNode
{
    DataType data;//数据
    struct ComplexNode *next;//指向下一个节点
    struct ComplexNode *random;//指向随机节点
} ComplexNode;

ComplexNode *BuyNode(DataType x)//产生新节点
{
    ComplexNode *tmp = (ComplexNode *)malloc(sizeof(ComplexNode));
    tmp->data = x;
    tmp->next = NULL;
    tmp->random = NULL;
    return tmp;
}

void PushBack(ComplexNode **pplist,DataType x)//尾插函数
{
    ComplexNode *cur = NULL;
    assert(pplist);
    cur = *pplist;
    if (*pplist == NULL)
    {
        *pplist = BuyNode(x);
    }
    else
    {
        while (cur->next)
        {
            cur = cur->next;
        }
        cur->next = BuyNode(x);
    }
}

ComplexNode *FindComplexNode(ComplexNode *plist,DataType x)//查找函数
{
    if (plist == NULL)
    {
        return NULL;
    }
    else
    {
        while (plist)
        {
            if (plist->data == x)
                return plist;
            plist = plist->next;
        }
        return NULL;
    }
}

ComplexNode *LineComplexNode(ComplexNode *plist)//第一步、产生节点并连接节点
{
    ComplexNode *phead = plist;
    ComplexNode *tmp = NULL;
    ComplexNode *ret = NULL;
    assert(plist);  
    while (plist)
    {
        ret = plist->next;
        tmp = BuyNode(plist->data);
        tmp->next = plist->next;
        plist->next = tmp;
        tmp->random = NULL;
        plist = ret;
    }
    return phead;
}

void RandomEvaluate(ComplexNode *plist)//第二步、random指针赋值
{
    assert(plist);
    while (plist)
    {
        if (plist->random == NULL)
        {
            plist->next->random = NULL;
        }
        else
        {
            plist->next->random = plist->random->next;
        }
        plist = plist->next->next;
    }
}

void PrintComplexNode(ComplexNode *plist)//打印节点
{
    while (plist)
    {
        printf("%d->",plist->data);
        plist = plist->next;
    }
    printf("NULL\n");
}

void PrintRandom(ComplexNode *plist)//打印random指向的数据
{
    while (plist)
    {
        if (plist->random == NULL)
        {
            printf("NULL->");
        }
        else
        {
            printf("%d->", plist->random->data);
        }
        plist = plist->next;
    }
    printf("STOP\n");
}

ComplexNode *ToPickComplexList(ComplexNode *plist)//摘出复杂链表
{
    ComplexNode *phead = NULL;
    ComplexNode *cur = NULL;
    ComplexNode *tmp = NULL;
    if (plist == NULL)
    {
        return NULL;
    }
    while (plist)
    {
        cur = plist->next;
        plist->next = cur->next;
        if (phead == NULL)
            phead = tmp = cur;
        else
        {
            tmp->next = cur;
            tmp = cur;
        }
        plist = plist->next;
    }
    return phead;
}

void Test()
{
    ComplexNode *plist = NULL;
    ComplexNode *tmp1 = NULL;
    ComplexNode *tmp2 = NULL;
    PushBack(&plist, 1);
    PushBack(&plist, 2);
    PushBack(&plist, 3);
    PushBack(&plist, 4);
    PushBack(&plist, 5);

    tmp1 = FindComplexNode(plist, 3);
    plist->random = tmp1;
    tmp1->random = NULL;
    tmp1 = FindComplexNode(plist, 2);
    tmp1->random = plist;
    tmp1 = FindComplexNode(plist, 4);
    tmp2 = FindComplexNode(plist, 5);
    tmp1->random = tmp2;
    tmp2->random = tmp2;//初始化复杂链表
    LineComplexNode(plist);//第一步
    RandomEvaluate(plist);//第二步
    tmp1 = ToPickComplexList(plist);//摘出链表

    PrintComplexNode(plist);//打印原始链表
    PrintRandom(plist);//打印原始Random所指向数据

    PrintComplexNode(tmp1);//打印新链表
    PrintRandom(tmp1);//打印新random所指向数据
}

int main()
{
    Test();
    return 0;
}

结果:

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值