链表相交和带环问题

一、题目
1、判断单链表是否带环?若带环,求环的长度?求环的入口点?
①链表是否带环问题。( 定义两个指针同时指向头节点,一个快指针,一个慢指针,两个指针同时遍历链表,快指针一次走两步,慢指针一次走一步,如果链表带环,两个指针一定会在环内相遇。例如两个人在操场同时跑步,跑得快的人一定会追上跑得慢的人。)
②在第一问中已经可以求得两指针相遇点,在定义一个指针,从相遇点出发开始遍历环,在此走到相遇点,便是一圈的长度,即环长。
③环的入口点见下图。
这里写图片描述
2、判断两个链表是否相交,若相交,求交点。(假设链表不带环)
问题思路看下图
这里写图片描述
3、判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
这里写图片描述
4、求两个已排序单链表中相同的数据。
这里写图片描述
二、代码及测试结果
1、判断单链表是否带环?若带环,求环的长度?求环的入口点?

SListNode *CircleSListNode(SListNode *list) //时间复杂度为O(n) 
{
    SListNode *slow,*fast;
    assert(list);
    slow=fast=list;
    while (fast && fast->_next)  //快指针走两步,慢指针走一步,若带环,则一定在环内相遇
    {
        slow=slow->_next;
        fast=fast->_next->_next;
        if (fast == slow)
        {
            return slow;  //返回相遇点地址
        }}
    return NULL;
}

size_t CircleLengthSListNode(SListNode *ps) //求环长,时间复杂度为O(n) 
{
    SListNode *tmp;
    size_t i=0;
    assert(ps);
    tmp =ps;
    do  //从环的相遇点开始走,走一圈便是环长
    {
        tmp=tmp->_next; 
        ++i;
    } while (tmp!=ps);
    return i;
}

SListNode *CircleEntrySListNode(SListNode *list,SListNode *meet) //时间复杂度为O(1) 
{
    SListNode *start;
    assert(list);
    start=list;
    while (meet != start)
    {
        meet=meet->_next;
        start=start->_next;
    }
    return meet;
}

测试代码及结果:

void Test13()
{
   // 判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。
    SListNode *entry,*end;
    printf("原链表:");
    SListPrint(SList);
    entry=SListFind(SList,1);
    end=SListFind(SList,18);
    end->_next=entry;

    printf("\n快慢指针相遇点地址:");
    printf("%p\n",CircleSListNode(SList));
    printf("\n环长:");
    printf("%d\n",CircleLengthSListNode(CircleSListNode(SList)));  //环长
    printf("\n环入口地址:");
    printf("%p\n",CircleEntrySListNode(SList,CircleSListNode(SList))); //环入口地址
    printf("\n环入口地址处数据:");
    printf("%d\n",CircleEntrySListNode(SList,CircleSListNode(SList))->_data); //环入口地址
}

链表带环
2、判断两个链表是否相交,若相交,求交点。(假设链表不带环)
代码:

int IsCross(SListNode* list1, SListNode* list2)  //判断是否相交,若尾节点地址相等则相交
{
    while (list1 && list1->_next)
    {
        list1 = list1->_next;
    }

    while (list2 && list2->_next)
    {
        list2 = list2->_next;
    }

    if (list1 == list2 && list1 != NULL)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

SListNode *SListCrossNode(SListNode *list1,SListNode *list2)  //交点地址
{
    SListNode *tmp1,*tmp2;
    DataType k=0;
    assert(list1 && list2);
    tmp1=list1;
    tmp2=list2;
    if(1 != (IsCross(list1,list2)))
        return NULL;
    while (tmp1->_next)    //遍历两个链表,求出链表的长度 
    {
        tmp1=tmp1->_next;
        k++;
    }
    while (tmp2->_next)
    {
        tmp2=tmp2->_next;
        k--;
    }
    tmp1=list1;
    tmp2=list2;
    if (k>0)   //让两个链表走到长度相等处
    {
        while (k--)
        {
            tmp1=tmp1->_next;
        }
    }
    else
    {
        k=abs(k);
        while (k--)
        {
            tmp2=tmp2->_next;
        }
    }
    while (tmp1!=tmp2) //两个链表同时从相等处开始走,走到有地址相等且不等于空则相交
    {
        tmp1=tmp1->_next;
        tmp2=tmp2->_next;
    }
    return tmp1;
}

测试代码及结果:

void Test14()
{
    SListNode *cross,*end,*entry;
    SListPushFront(&list1,5);  //头插
    SListPushFront(&list1,15);
    SListPushBack(&list1,10);  //尾插
    SListPushBack(&list1,12);
    SListPushBack(&list1,11);
    SListPushFront(&list1,25);
    SListPushFront(&list1,35);
    SListPushBack(&list1,28);
    SListPushFront(&list1,25);
    SListPushFront(&list1,35);
    printf("链表1:");
    SListPrint(list1);

    SListPushBack(&list2,444);  //尾插
    SListPushBack(&list2,56);
    SListPushBack(&list2,0);
    SListPushBack(&list2,15);
    SListPushBack(&list2,25);
    SListPushFront(&list2,18);
    SListPushFront(&list2,35);
    printf("链表2:");
    SListPrint(list2);

    cross=SListFind(list2,25);
    cross->_next=SListFind(list1,10);

    printf("\n交点:");
    printf("%p\n",SListCrossNode(list1,list2)); //两链表是否相交
    printf("%d\n",SListCrossNode(list1,list2)->_data); 

两链表相交 不带环
3、判断两个链表是否相交,若相交,求交点。(假设链表可能带环)。

SListNode* SListIsCross(SListNode *list1,SListNode *list2) 
{
    SListNode *meet1,*meet2;;
    assert(list1&&list2);
    meet1=CircleSListNode(list1);  //判断 两个链表是否带环
    meet2=CircleSListNode(list2);
    if (meet1 && meet2 )  //两个链表带环
    {
        SListNode *tmp=meet1->_next;
        while (tmp!=meet1)  //判断是否带同一个环
        {
            if (tmp==meet2) //带同一个环
            {
                SListNode *cur1,*cur2;
                cur1=CircleEntrySListNode(list1,meet1);
                cur2=CircleEntrySListNode(list2,meet2);
                if (cur1==cur2)  //环外相交
                {
                    SListNode *tmp1,*tmp2;
                    tmp1=list1;
                    tmp2=list2;
                    while (tmp1 != cur1)
                    {
                        tmp1=tmp1->_next;
                    }
                    tmp1->_next=NULL;
                    while (tmp2 != cur2)
                    {
                        tmp2=tmp2->_next;
                    }
                    tmp2->_next=NULL;
                    return SListCrossNode(list1,list2);  //返回交点地址
                }
                else  //环内相交
                {
                    return cur1; //返回交点地址
                }
            }
            tmp=tmp->_next;
        }
        return NULL;   //带两个不同的环 
    }
    else if (NULL==meet1 && NULL==meet2) //两个链表都不带环
    {
        return SListCrossNode(list1,list2); 
    }
    else  //可能一个带环
    return NULL;
}

测试代码及结果:

    SListNode *cross,*end,*entry;
    SListPushFront(&list1,5);  //头插
    SListPushFront(&list1,15);
    SListPushBack(&list1,10);  //尾插
    SListPushBack(&list1,12);
    SListPushBack(&list1,11);
    SListPushFront(&list1,25);
    SListPushFront(&list1,35);
    SListPushBack(&list1,28);
    SListPushFront(&list1,25);
    SListPushFront(&list1,35);
    printf("链表1:");
    SListPrint(list1);

    SListPushBack(&list2,444);  //尾插
    SListPushBack(&list2,56);
    SListPushBack(&list2,0);
    SListPushBack(&list2,15);
    SListPushBack(&list2,25);
    SListPushFront(&list2,18);
    SListPushFront(&list2,35);
    printf("链表2:");
    SListPrint(list2);

    cross=SListFind(list2,25);
    cross->_next=SListFind(list1,10);

    entry=SListFind(list1,5);
    end=SListFind(list1,28);
    end->_next=entry;
    printf("\n交点:");
    printf("%p\n",SListIsCross(list1,list2));  //判断两链表相交(可能带环)
    printf("\n%d\n",SListIsCross(list1,list2)->_data);
}

两链表相交且带环
4、求两个已排序单链表中相同的数据

void SListUnionData(SListNode *list1,SListNode *list2)
{
    SListNode *tmp1,*tmp2;
    assert(list1 && list2);
    tmp1=list1;
    tmp2=list2;
    while (tmp1 && tmp2)
    {
        if (tmp1->_data<tmp2->_data)  //小的指针向前走一步
        {
            tmp1=tmp1->_next;
        }
        else if(tmp1->_data>tmp2->_data)
        {
            tmp2=tmp2->_next;
        }
        else  //数据相等时同时走
        {
            printf("%d ",tmp2->_data);
            tmp1=tmp1->_next;
            tmp2=tmp2->_next;
        }
    }
    printf("\n");
}

测试代码及结果:

void  Test15()
{
    SListPushFront(&list1,5);  //头插
    SListPushFront(&list1,15);
    SListPushBack(&list1,10);  //尾插
    SListPushBack(&list1,12);
    SListPushBack(&list1,11);
    SListPushFront(&list1,25);
    SListPushFront(&list1,3);
    SListPushBack(&list1,28);
    SListPushFront(&list1,2);
    SListPushFront(&list1,35);
    SeqListSort(list1);   //冒泡排序
    printf("链表1:");
    SListPrint(list1);

    SListPushBack(&list2,4);  //尾插
    SListPushBack(&list2,56);
    SListPushBack(&list2,0);
    SListPushBack(&list2,15);
    SListPushBack(&list2,25);
    SListPushFront(&list2,18);
    SListPushFront(&list2,35);
    SeqListSort(list2);
    printf("链表2:");
    SListPrint(list2);
    printf("相同的数据:");

    SListUnionData(list1,list2);//求两个已排序单链表中相同的数据。
}

这里写图片描述

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
约瑟夫环问题是一个经典的问题,可以用链表和类的方式来求解。下面是一个用链表和类求解约瑟夫环问题的示例代码: ```python class Node: def __init__(self, value=None): self.value = value self.next = None class JosephusCircle: def __init__(self, n, m): self.head = Node(1) cur = self.head for i in range(2, n+1): cur.next = Node(i) cur = cur.next cur.next = self.head self.m = m def eliminate(self): cur = self.head while cur.next != cur: count = 1 while count != self.m: cur = cur.next count += 1 print("Node %d is eliminated." % cur.next.value) cur.next = cur.next.next print("Node %d survives." % cur.value) n = 10 m = 3 jc = JosephusCircle(n, m) jc.eliminate() ``` 在这个示例代码中,我们首先定义了一个 `Node` 类来定义链表的节点,其中 `value` 属性表示节点的值,`next` 属性表示下一个节点的引用。 然后我们定义了一个 `JosephusCircle` 类来实现约瑟夫环问题的求解,其中 `n` 表示总人数,`m` 表示每次淘汰的人数。在构造函数中,我们首先创建了一个包含 `n` 个节点的循环链表,并且将最后一个节点的 `next` 属性指向头节点,这样就形成了一个约瑟夫环。然后我们定义了一个 `eliminate` 方法来模拟淘汰过程,直到只剩下一个人为止。 在 `eliminate` 方法中,我们首先从头节点开始遍历链表,每次遍历 `m` 个节点,然后将第 `m` 个节点从链表中删除。直到链表中只剩下一个节点为止,这个节点即为最后生还的人。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙跃十二

写的不错,给点鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值