算法:得到两条链的长度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;
}
测试结果: