问题1:
给出两个链表的头指针,判断这两个链表是否相交。假设两个链表均不带环。
解法一:
如果两个链表都无环,则可以把第二个链表接在第一个链表后面,如果得到的链表有环,则说明这两个链表相交。这里如果有环,则第二个链表的表头一定在环上,只需要从第二个链表开始遍历,看是否会回到起点即可判断。假设两个链表长度分别为m和n,则时间复杂度为O(m+n)。
解法二:
先分别统计出两条链表中的结点总数count1,count2,此时让长的链表先从头走(count1-count2)步(假设链表1长于链表2),然后两个指针一起向后走直到两个指针指向同一个结点,此时这个结点就是不带环链表的相交点;
int Check_Cross(pLinkList plist1,pLinkList plist2)
{
//判断链表是否相交,两个链表均不带环
pLinkNode p1=plist1->phead;
pLinkNode p2=plist2->phead;
if((p1 == NULL)||(p2 == NULL)) //空链表
{
return -1;
}
while(p1->next)
{
p1=p1->next;
}
while(p2->next)
{
p2=p2->next;
}
//p1,p2分别指向链表plist1,plist2的最后一个结点
//通过判断最后一个结点是否相同来判断两条链表是否相交
if(p1 == p2)
return 1; //相交
return 0;
}
pLinkNode GetLink_EntryNode(pLinkList plist1,pLinkList plist2)
{
//统计出两个链表的结点总数count1,count2
//让较长的链表走count1-count2步
//两个链表一起走直到相遇则返回相遇结点的地址
int count1=0;
int count2=0;
pLinkNode cur1=NULL;
pLinkNode cur2=NULL;
assert(plist1);
assert(plist2);
cur1=plist1->phead;
cur2=plist2->phead;
while(cur1) //统计链表1的总结点数
{
count1++;
cur1=cur1->next;
}
while(cur2) //统计链表2的总结点数
{
count2++;
cur2=cur2->next;
}
cur1=plist1->phead;
cur2=plist2->phead;
if(count1-count2 >= 0)
{
while(count1-count2 != 0)
{
cur1=cur1->next;
count1--;
}
if(cur1 != cur2)
{
cur1=cur1->next;
cur2=cur2->next;
}
}
else
{
while(count2-count1 != 0)
{
cur2=cur2->next;
count2--;
}
if(cur1 != cur2)
{
cur1=cur1->next;
cur2=cur2->next;
}
}
return cur1;
}
pLinkNode _GetLink_EntryNode(pLinkList plist1,pLinkList plist2)
{
//构造成环的方法求两个链表的交点
pLinkNode meet=NULL;
pLinkNode cur=NULL;
assert(plist1);
assert(plist2);
cur=plist1->phead;
//构造环
while(cur->next)
{
cur=cur->next;
}
cur->next=plist2->phead;
//找出环的相遇结点
meet=Check_Cycle(plist1);
//求出环的入口点
return GetCircle_EntryNode(plist1,meet);
}
问题2:
假设链表可能带环
如果链表带环,可能会出现以下几种情况
通过上图我们可以发现如果通过调用函数Check_Cycle则可以找到带环链表的相遇点
1).如果一条链表带环,一条链表不带环,那仫这两条链表必然是不相交的
2).如果两条链表都带环则属于上述的情况三,此时如何区分这三种情况呢?通过观察发现,第一种情况带环但是不相交,后两种情况带环属于相交的情况;我们知道只要链表带环则必然可以求出相遇点的,此时就可以根据判断两个相遇点是否在一个环内来排除情况一啦…如果两个相遇点在同一个环内,此时就要区分交点在环内和交点在环外的情况了:如果交点在环外则两条链表公用同一个环则只有一个入口点,如果交点在环外虽然他们也公用同一个环但是通过上图发现此时有两个入口点,这种情况的交点就是这两个入口点之一选择其中的一个输出就可以了;
3).在上述情况中通过判断入口点的方式区分了交点在环内和交点在环外两种情况,那仫如何求出交点在环外情况的交点呢?当然在之前已经求过了环的入口点,如果我们让环的入口点指向另一条链表的第一个结点(构成新环)则此时再求出环的入口点,这个入口点就是交点;
int _Check_Cross(pLinkNode meet1,pLinkNode meet2)
//两条链表都带环判断链表是否相交
{
pLinkNode m1=meet1;
pLinkNode m2=meet2;
while(m1 != m2)
{
m1=m1->next;
}
if(m1 == m2)
return 1;//链表相交
return 0;
}
pLinkNode EntryNode(pLinkList plist1,pLinkList plist2,pLinkNode start1)
{
pLinkNode s=start1;
pLinkNode meet=NULL;
assert(plist1);
assert(plist2);
while(s->next != start1)
{
s=s->next;
}
s->next=plist2->phead;
meet=Check_Cycle(plist1);
return GetCircle_EntryNode(plist1,meet);
}