问题:
1、如何判断一个链表是不是有环?
2、如果链表为存在环,如何找到环的入口点?
3、判断两个链表是否相交,若相交求交点。
网上很多:
一、判断单链表是否有环
typedef struct LinkedList{
int data;
LinkedList* pNext;
}LinkedList;
bool i***istLoop(LinkedList* pList)
{
if (pList == NULL || pList->pNext == NULL)
return false;
LinkedList* p1 = pList;
LinkedList* p2 = pList;
while (p2 != NULL && p2->pNext != NULL)
{
p1 = p1->pNext;
p2 = p2->pNext->pNext;
if (p1==p2)
return true;
}
return false;
}
二、找到环的入口点
当fast若与slow相遇时,slow肯定没有走遍历完链表。证明:
如图,slow从H走到A时,fast一定在环上某处C(或B或D)。设此时slow走过了HA=x,fast前方距环入口点距离CDA=y,环周长为r。slow继续沿ABC方向前行y,则同时fast也前行了2y刚好追上slow,二者相遇,这时slow还要经过(r-y)才遍历完一个链表总长L。因为y是环上一点距入口A的长度,所以r-y>0,得证。
H________A____B
|____|
D C
当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。
假设slow走了s步,则fast走了2s步(fast步数还等于s加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L - a - x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,
于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
程序描述如下:
slist * FindLoopPort(slist * head)
{
slist * slow = head, * fast = head;
while ( fast && fast -> next )
{
slow = slow -> next;
fast = fast -> next -> next;
if ( slow == fast ) break ;
}
if (fast == NULL || fast -> next == NULL)
return NULL;
slow = head;
while (slow != fast)
{
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
类似的解释:
|------ n ------|
H____h____A__c__Meet
|_____|r
在p2和p1第一次相遇的时候,假定p1走了n步,环路的入口是在h步的时候经过的,那么有
p1走的路径: h+c = n; c为p1和p2相交点,距离环路入口的距离
p2走的路径: h+c+k*r = 2*n; r为环路的周长,k是整数
显然,如果从h+c点开始,p1再走n步骤的话,还可以回到h+c这个点
同时p2从头开始走的话,经过n步,也会达到h+c这点
显然在这个步骤当中p1和p2只有前h步走的路径不同,所以当p1和p2再次重合的时候,必然是在链表的环路入口点上。
1。可以先分别遍历找出两个链表的尾节点,如果连个尾节点相同,则两个链表相交。程序描述如下:
//找到list1的最后一个节点p1
p1=head1
while(p1->next不是NULL)
p1=p1->next
找出list2的最后一个节点p2
if(p1==p2)
相交
else
不相交
时间复杂度:O(list1.length + list2.length)
空间复杂度:O(1)
2。使用hash表
loop:p1从head1到最后一个节点
把p1放入hash表table中
loop:p2从head2到最后一个节点
if(p2在hash表中)
相交
时间复杂度:O(list1.length + list2.length)
空间复杂度:O(list1.length)
扩展问题:两个链表都不存在环,如果相交,给出相交的第一个点。
比较好的方法有两个:
一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。O(list2.length)
>--- 大于号是两个链表,'-- '是相交重合部分。
二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。
这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。
阅读(5961) | 评论(0) | 转发(0) |