判断单链表是否有环并找到入口处以及判断两个单向链表是否相交

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值