1.判断单向链表是否有环
判断一个单链表是否有环一般采用快慢指针方法,设置两个指针p1,p2,将p1设置为慢指针,p2设置为快指针,p1每次只走一步,而p2每次走两步,这样如果存在环,则p1与p2一定会相遇(这是因为p2每次都只比p1快一步,假设有环,并且环的节点个数为r,那么p2进入环以后会绕着环转圈,当p1进入环后,肯定会和p2相遇,并且相遇的时候p2-p1=n*r,n>=1,此时p2在环中转了至少一圈),如果不存在环,那么p2会首先指向NULL,作为结束条件。
int isExistLoop(Node* head)
{
Node* p1=head;
Node* p2=head;
while(p2==NULL||p2->next==NULL)
{
p1=p1->next;
p2=p2->next->next;
if(p1==p2)
return 1;
}
return 0;
}
2. 找到单向链表环的入口处
假设p为起点到入口处的距离,v为入口处到判断快慢指针相遇时的距离
首先要确定的是从起点到相遇处慢指针所走的距离为p+v=n*r,n>=1;这是因为p2-p1=2*p1-p1=n*r,p1即为慢指针从起点到相遇的距离,那么我们可以在相遇处重新设置一个指针p_meet,在起点处重新设置一个指针p_start,让这两个指针同时出发,并且速度一样,那么我们可知在这两个指针相遇的时候他们所走的路程一样,即S(p_meet)=S(p_start),由于p+v=n*r,那么p=n*r-v,假设p_star此时t已经走了p-1的距离,(此时肯定没有相遇),那么对于p_meet来说,走了路程n*r-v-1,因此,无论n为多少,p_meet都会停在入口处前一处的地址(n*r-v-1),此时,p_start向前走一个,p_meet也向前走一个,p_start最终会和p_meet在入口处相遇,因此,当p_start与p_meet第一次相遇时,此处即为入口地址。
Node* FindInputpoint(Node* head)
{
Node* p1=head;
Node* p2=head;
Node* p_meet;
Node* p_start=head;
while(p2==NULL||p2->next==NULL)//判断是否有环
{
p1=p1->next;
p2=p2->next->next;
if(p1==p2)
break;
}
p_meet=p2;
if(p_meet==NULL||p_meet->next==NULL)
return NULL;
while(p_meet!=p_start)//判断入口处
{
p_meet=p_meet->next;
p_start=p_start->next;
}
return p-start;
}
3. 判断两个单向链表是否相交,此处要明确一个问题,就是两个链表相交不会出现X形状的链表,因为每个节点只有一个next,那么在相交节点处总会指向同一个地址,因此,如果两个链表相交,那么这两个链表组成的形状就一定是Y字型的,因此对于两个链表head_1,head_2来说,判断是否相交,可以有两种方法:
1). 可以将head_2(head_1)链表的尾端指向链表head_1(head_2)的头结点,那么再判断此链表是否有环,如果有环,表明相交,如果没环,则从head_2(head_1)开始遍历,最终会指向NULL。
int isCross(Node* head_1,Node* head_2)
{
Node* p1=head_1;
Node* p2=head_2;
while(p1->next)
{
p1=p1->next;
}
p1->next=p2;//将head_1的末端接到head_2
Node* slow=head_1;
Node* fast=head_1;
while(!fast||!fast->next)//判断是否有环
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
return 1;
}
return 0;
}
2). 如果两个链表相交,那么可知两个链表的末端肯定会是同一个结点(Node),即肯定会形成Y字形的链表,因此我们可以判断两个链表的终端是否相等,以此来判断是否相交
int isCross(Node* head_1,Node* head_2)
{
Node* p1=head_1;
Node* p2=head_2;
while(p1->next)
{
p1=p1->next;
}
while(p2->next)
{
p2=p2->next;
}
if(p1==p2)
return 1;
else
return 0;
}