给定两个单链表,判断是否有交点,如果有则返回第一个交点

算法:得到两条链的长度m和n,再定义两个指针p1和p2,分别指向两条链的开头,如果m>n,则让p1先走m-n步,如果n>m,则让p2先走n-m步,然后两个指针再一起走,相遇的第一个点就是第一个交点,若不相遇则没有交点。(两个链表都无环)

(相交的特征:只要两条链表相交,则从第一个交点开始后面的节点都相交)

注:还要就链表是否有环的情况进行分类讨论。

      (1)如果一个有环一个无环则肯定不相交

      (2)都有环但是两个链表不相交

      (3)都有环且相交

有环情况的处理方法:将两个有环的链表都断开,然后按照无环的情况处理,注意最后还要把断开的环接上

代码:

Node *FirstIntersection(List plist1,List plist2)
{
     Node *p = IsCircle(plist1);
	 Node *q = IsCircle(plist2);
	 if(p==NULL && q!=NULL || p!=NULL && q==NULL)    //如果一个有环一个没环则一定不相交
	 {
	    return NULL;
	 }
	 Node *pnext=NULL;
	 Node *qnext=NULL;
	 if(p!=NULL)                                     //如果p有环
	 {
	    pnext=p->next;                               //断开环
	    p->next=NULL;
	 }

	 if(q!=NULL)                                     //如果q有环
	 {
		 qnext=q->next;                              //断开环
		 q->next=NULL;
	 }

	 int m=GetLength(plist1);
	 int n=GetLength(plist2);
	 Node *p1=plist1->next;                              //定义两个指针分别指向两个链表的开头
	 Node *p2=plist2->next;
	 while(m>n)                                          //如果m长,就让p1先走m-n步
	 {
	   p1=p1->next;
	   m--;
	 }
	 while(n>m)                                          //如果n长,就让p2先走n-m步
	 {
	   p2=p2->next;
	   n--;
	 }
	 while(p1!=NULL && p2!=NULL)                         //如果p1和p2有一个走到空,说明没有交点
	 {
	    if(p1 == p2)                                     //如果在走到空之前p1=p2了说明有交点
		{
		   break;
		}
	 
		p1=p1->next;
		p2=p2->next;
	 }
	 if(p1==p2 && p1!=NULL)                              //如果有交点返回交点
	 {
	    return p1;
	 }
	 else
	 {
		 return NULL;
	 }
	 if(pnext != NULL)                        //还原环
	{
		p->next = pnext;
	}
	if(qnext != NULL)
	{
		q->next = qnext;
	}

}

测试代码:

int main()
{
	//先测两条没有交点的链
	Node head1;
	Node head2;
	InitList(&head1);
	InitList(&head2);
	for(int i=0;i<10;i++)//构造两条不相交的链表
	{
		Insert_tail(&head1,i);
		Insert_tail(&head2,i+100);
	}

	Node *p = FirstIntersection(&head1,&head2);
	if(p == NULL)
	{
		printf("没有交点\n");
	}
	else
	{
		printf("第一个交点为%d\n",p->data);
	}

	//构造一个环
	Node *q = Search(&head1,3);
	Node *r = Search(&head1,9);
	assert(q!=NULL && r!=NULL && r->next==NULL);
	r->next = q;

	p = FirstIntersection(&head1,&head2);
	if(p == NULL)
	{
		printf("没有交点\n");
	}
	else
	{
		printf("第一个交点为%d\n",p->data);
	}
	//再测head1的环是否还原
	p = IsCircle(&head1);  
	if(p == NULL)
	{
		printf("没有环\n");
	}
	else
	{
		printf("有环\n");
	}

	//构造两条有交点的无环链表
	Node head3;
	Node head4;
	InitList(&head3);
	InitList(&head4);
	for(int i=0;i<10;i++)
	{
		Insert_tail(&head3,i);
	}

	Insert_tail(&head4,20);
	Insert_tail(&head4,21);

	p = Search(&head3,3);
	q = Search(&head4,21);
	assert(p!=NULL && q!=NULL && q->next==NULL);
	q->next = p;//3为两条链的第一个交点

	p = FirstIntersection(&head3,&head4);
	if(p == NULL)
	{
		printf("没有交点\n");
	}
	else
	{
		printf("第一个交点为%d\n",p->data);
	}
	
	Show(&head3);
	Show(&head4);

	//构造两个个相交的且有环的链表
	p = Search(&head3,5);
	q = Search(&head3,9);
	assert(p!=NULL && q!=NULL && q->next==NULL);
	q->next = p;  //构造环

	p = FirstIntersection(&head3,&head4);
	if(p == NULL)
	{
		printf("没有交点\n");
	}
	else
	{
		printf("第一个交点为%d\n",p->data);
	}

	return 0;
}

测试结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值