关于链表以及链表相交问题

在c语言中,链表是一个重要的板块,也是一个较难的板块,这里我这下我平时写链表题目的一些小心得。

1:链表的是由一个一个节点相连而成,每一个节点都由数据域以及指针域组成,这里有个重要的地方是指针域应该是指向自己的一个指针变量,如下:

struct node{

datatype   data;

struct  node *next;

}*Node;

此处的datatype指的是数据的类型,可以是int,float之类的,也可以是自定义的机构体类型。

2:在最开始的时候,需要为链表的头结点开辟一个空间,如下:

struct Node head,

head=(node*)malloc(sizeof(node));

head->next=NULL;

这样就开辟了一个头结点,这个头结点没有数据,只是用来指向链表而已,方便后续对链表操作而已。

3:之后一个需要解决的操作是为链表添加后续指针,这里就需要开辟一个新的空间,并且没添加一次就需要开辟一次,如下:

struct Node p,s;

s=head;

p=(node*)malloc(sizeof(node));

scanf(“%d”,p->data);

s->next=p;

s=p;

这里用的尾插法,需要注意的是,当你不想继续输入数据或者已经跳出循环后,要将s->next设为NULL,否则这个链表就出错啦(我之前也在这犯过错)

7aefc0c7fd4a44d2860ab9bbd8e004db.jpg

之后就是输出了,可以用while循环,操作如下:

struct node e;                       

e=head->next;//此处因为head没有数据,所

//以指向next

while(e!=NULL)

{

printf(“%d”,e->data);

e=e->next;

}

这样就可以啦,一个新鲜的链表就出来了

8d00dd078c054634a5ff9e216f7e65a0.jpg

但是你以为能够熟练创建一个链表就已经结束了吗?nonono,还有好多难题呢,这里有一个问题:如何查看两个单链表是否相交,并且返回相交节点?

这个时候大家估计都在想,两个链表相交还不简单?直接找到最末端的地方,看地址相不相同不就行了吗?确实,这是一般的思路,但是,要是这两个链表都成环了呢?你怎么知道他们相交了呢?

01b0fe55a62f460cab49386e8e2c1e4e.jpg

 想迷糊了吧。

其实也很简单。

首先,这问题分三种情况讨论:

1)两个链表都没成环,那么就直接比较最末端的地址就是了,相同则相交

2)一个成环,一个未成环,这种情况是绝对不会相交的,大家可以自己想想为什么。

3)一种是两个都成环了,而这里又分相交与没相交两种情况,而相交又分两种情况,是在入环前相交还是在入环后相交的?

把这三种情况考虑到了后再去做题。

首先是如何查看链表是否成环:

这就要利用快慢指针了,让快慢指针依次遍历这个链表,若是会相遇,则一定成环,然后让慢指针继续遍历,快指针从头重新遍历,但是快指针的速度和慢指针一样,它们之后一定会在入环节点相遇,然后返回这个入环节点就是了,思路很简单,代码也是:

struct Node findloop(struct Node head)

{

        if(head==NULL)
        return NULL;
        if(head->next==head)
        return head;
        struct Node fast,slow;
        fast=head->next;
        slow=head;
        int flag=1;//flag=1则表示为成环
        while(fast!=NULL&&fast->next!=NULL)
            {
                fast=fast->next;
                slow=slow->next;
                if(slow==fast)
                {
                    flag=0;
                    break;//相等就跳出循环
                }
            }
        if(flag==0)
            {
                fast=head; 
                while(slow!=fast)
                {
                    slow=slow->next;
                    fast=fast->next;
                }
                return fast;//返回成环结点    
            }
        else    
        return false;

}

这里是我借鉴了其他大佬的代码写出来的,大家可以画图来自己思考为什么这样写。

 9a4b209399ce40189bf50cb8c6c0fd49.jpg 

       这里就找到了入环结点,当两个链表都返回了一个结点说明都成环,一个为NULL一个有结点就可以直接说明未相交了,而都为NULL就说明都不成环。

接着我们来检测未成环的链表是否相交

检测代码如下:

struct Node fun(struct Node head1,struct Node head2)

{                                                                 

   struct Node s1,s2;
    s1=head1->next;
    s2=head2->next;
    while(s1->next!=NULL)
    s1=s1->next;
    while(s2->next!=NULL)
    s2=s2->next;
    if(s1==s2)
        return 1;
    else
        return 0;

}               

     

若是检测出有相同,就要去寻找相交结点在哪儿,代码如下:

struct Node fun(struct Node head1,struct Node head2)
{ 
    struct Node s1,s2;

    s1=head1->next;

    s2=head2->next;

               int n=0;

           while(s1!=NULL)

            {

                s1=s1->next;

                n++;
            }                

            while(s2!=NULL)

            {

                s2=s2->next;

                n--;

            }

            s1=n>0?head1:head2;//让s1指向长的链表。

            s2=(s1==head1)?head2:head1;//s2指向s1之外的链表

            n=fabs(n);

            while(n!=0)

            {
    
                s1=s1->next;

            n--;
            }

            while(s1!=s2)

            {

                //两个结点相等了就跳出循环

                s1=s1->next;

                s2=s2->next;


            }

            

                    return s1;

}

解决完未成环的链表相交问题后,就得解决成环链表相交问题了。

首先需要判断成环链表是否相交,利用上面的求入环结点的函数,判断入环结点是否相同,相同则是在成环之前就相交了,若是成环之前就相交,就将入环结点看成是NULL来找相交结点

代码如下:

struct Node find1(struct Node head1,struct Node head2,struct Node loop)
{
        struct Node s1,s2;
        s1=head1->next;
        s2=head2->next;
        int n=0;
        while(s1!=loop)
        {
            s1=s1->next;
            n++;
        }
        while(s2!=loop)
        {
            s2=s2->next;
            n--;
        }
        s1=n>0?head1:head2;
        s2=(s1==head1)?head2:head1;
        n=fabs(n);
        while(n!=0)
           {
                n--;
                s1=s1->next;
            }
        while(s1!=s2)
        {
            s1=s1->next;
            s2=s2->next;
        }
            return s1;
}    

之后就是另一种情况,那就是成环后相交;

这种情况需要和成环不相交进行区别,所以需要将两个链表的入环结点来判断,使得一个入环结点不动,另一个移动,若是相遇到了,则是成环后相交,若是转了一圈还是没找到,那就是成环后不相交;

代码如下:

struct Node (struct Node head1,struct Node head2,struct Node loop1,struct Node loop2)
{
        struct Node s1,s2,s3;
         s1=loop1;
         s2=loop2;
         s3=loop1->next;
         while(s3!=s1)
            {
                    s3=s3->next;
                    if(s3==s2)
                        return s2;//若是s3在循环路上遇到了s2说明相交,返回一个就行
             }
        return NULL;
           
}

以上就是链表相交问题的大概思路了,新人还不是很熟练,希望大佬们多多指点。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值