判断两个链表是否相交,《编程之美》给出了以下方法:
1.判断第一个链表的每个节点是否在第二个链表中,这种方法的时间复杂度为:O(length(h1)*length(h2)),这种方法很耗时间
2.利用计数的方法 一个简单的做法是对第一个链表的结点地址进行hash排序,建立hash表,然后针对第二个链表的每个节点的地址查询hash表,如果它在哈希表中出现,那么说明第二个链表和第一个链表有共同的结点,这个方法的时间复杂度为O(length(h1)+length(h2)),但是它同时需要附加O(length(h1))的存储空间,以存储哈希表。
3.由于两个链表都没有环,我们可以把第二个链表接在第一个链表后面,如果得到的链表有环,则说明这两个链表相交。否则,这两个链表不相交。
4.先遍历第一个链表,记住最后一个结点,然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个结点做比较,如果相同,则相交;否则,不相交。
本文针对链表有环无环的情况,分别分析了判断是否相交的方法。(1)如果两个链表都没有环,使用《编程之美》给出的解法4,(2)如果两个链表,一个有环,一个没有环,则这两个链表一定不相交(3) 如果两个链表都有环,则分别找到两个链表的环中的一个结点N1和N2(找环中的结点的方法在下面有介绍)。遍历第一个链表的环,看第二个链表的环的某个结点N2是否出现在第一个链表的环中,如果出现,两个有环链表是相交的,否则,两个链表是不相交的。
上面的情况(3)中需要找出有环链表的环中的某个结点,方法和判断链表有环的方法类似。判断链表有环的方法是:定义一个快的指针,每次移动两步,定义一个慢的指针,每个移动一步,如果链表有环,快的指针一定可以追上慢的指针,如果没有环,则两个指针没有相遇的时刻。怎样找出环中的某个结点,利用上面的快指针和慢指针,他们相遇的点必定在环中,相遇的时刻将这个结点返回,即可找到环中的一个结点。
判断链表是否有环,程序为:
int hasloop(node *head)
{
node *fast=head; //定义两个指针
node *slow=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow) //如果有环,两个指针会相遇
return 1;
}
return 0;
}
判断有环的程序在下面会用到,判断两个链表是否相交的程序为:
int isjoin(node *head1,node *head2)
{
if(hasloop(head1)+hasloop(head2)==0) //两个链表都没有环,只需判断最后一个结点是否相同
{
node *p=head1;
node *p1=head2;
while(p->next)
p=p->next;
while(p1->next)
p1=p1->next;
return p1==p;
}
else if(hasloop(head1)+hasloop(head2)==1) //两个链表有一个有环,另外一个没有环,这时两个链表不相交
{
cout<<"not joint"<<endl;
return 0;
}
else //两个链表都有环的情况
{
node *fast=head1;
node *slow=head1;
node *entry1=0;
node *entry2=0;
node *p=head2;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow)
{
entry1=fast; //entry1为第一个链表中的某个结点
break;
}
}
fast=head2;
slow=head2;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow)
{
entry2=fast; //entry2为第二个链表中的某个结点
break;
}
}
fast=entry1;
slow=entry1;
while(fast&&fast->next) //遍历第一个链表的环,查看entry2是否出现,若出现,则相交
{
slow=slow->next;
fast=fast->next->next;
if(slow==entry2)
return 1;
if(fast==slow)
{
break;
}
}
return 0;
}
}