判断单链表是否有环

链表结构:

struct List
{
	int data;
	List* next;
};


(1)判断单链表是否有环

采用追赶法,设置两个指针p和q,从链表表头开始,p每一步走两个节点,q每一步走一个节点,如果链表有环则p和q必相遇。

代码如下

// 判断链表是否有环,时间复杂度O(n),空间复杂度O(1)
List* hasLoopInList( List* head )
{
	List *p, *q;
	p = q = head;
	
	do 
	{
		if ( p->next != NULL && q->next != NULL )
		{
			p = p->next->next;
		}
		else
		{
			return NULL;
		}
		q = q->next;
	} while ( p != q );

	return p;
}

(2)找到环的起始入口(交叉点)

设链表总长度为L,链表头节点到交叉点的距离为x,环长为y,则L=x+y;

设节点p和q共走了s步相遇,由于p每次走两个节点,q每次走一个节点,因此p共走2s个节点,q共走s个节点;

设p与q相遇时,p共绕环走了n圈(n>=1),q绕环第一圈未走完,q和p相遇点距环其实节点为a=s-x;

则p所走总节点数2s满足:2s=ny+x+a=ny+x+(s-x)=ny+s;

由上式进一步得到:ny=s=a+x   => a=ny-x;

从而相遇点顺着环的方向再经过r=y-a=个节点到达环的起始入口;

由a=ny-x带入r=y-a,得到r=x-(n-1)y,即x=r+(n-1)y;

因此若设置两个指针,一个从链表头节点开始每一步走一个节点,另一个从相遇点开始每一步走一个节点,则两指针必定在环的起始入口相遇。

根据以上分析,实现找出环起始入口的代码为:

// 如果有环,返回环的起始节点,时间复杂度小于O(n),空间复杂度O(1)
List* findStartNodeOfLoopInList( List* head, List* meetNode )
{
	if ( head == NULL || meetNode == NULL ) return NULL;
	
	List* p = head;
	List* q = meetNode;

	while( p != q )
	{
		p = p->next;
		q = q->next;
	}

	return p;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值