通俗易懂说单链表(2)链表/环长度、有环,环入口

1. 单链表长度

//计算单链表长度
int lengthNode(Node *node)
{
	if (NULL == node)
	{
		cout << "error" << endl;
		return 0;
	}
	int iLen = 0;
	Node *pTmp = node;
	while (pTmp->next) //从头到尾遍历链表,计数器依次累加
	{
		pTmp = pTmp->next;
		iLen++;
	}
	return iLen;
}

2. 单链表是否有环?

2.1 思想

设置两个指针,都指向头结点,一个走的快,一个走的慢,
如果有环,那么若干步以后,快指针总会超过慢的指针一圈;
如果没有,那么若干步以后,快指针指向NULL。

2.2 代码实现

//单链表定义
typedef struct node {
	int val;
	struct node *next;
}Node,*pNode;

//判断单链表是否有环  
bool isLoop(pNode pHead)  
{  
	//省略判断pHead有效
	//定义两个临时变量 快慢指针
	pNode fast = pHead;  
	pNode slow = pHead;  
	//如果无环,则fast先走到终点  
	//当链表长度为奇数时,fast->Next为空  
	//当链表长度为偶数时,fast为空  
	while( fast != NULL && fast->next != NULL)  
	{  
		fast = fast->next->next;  
		slow = slow->next;  
		//如果有环,则fast会超过slow一圈  
		if(fast == slow)  
		{  
			break;  
		}  
	}  

	if(fast == NULL || fast->next == NULL  )  
	{	
		return false;  
	}
	else  
	{
		return true;  
	}
} 

3. 单链表环入口

3.1 思想

第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,
因此,慢,快指针分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。

3.1.1 证明

在环上相遇后,假设起始点到环入口长度为 len1,环入口到相遇点位置为 len2,环长度为R,则:
慢指针: S = len1 + len2
快指针: 2S = len1 + R + len2
所以推到出: len1 = R - len2
即证明了第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离。

3.2 代码实现

	Node* findLoopEntrance(pNode pHead)  
{  
	pNode fast = pHead;  
	pNode slow = pHead;  
	while( fast != NULL && fast->next != NULL)  
	{  

		fast = fast->next->next;  
		slow = slow->next;  
		//如果有环,则fast会超过slow一圈  
		if(fast == slow)  
		{  
			break;  
		}  
	}  
	if(fast == NULL || fast->next == NULL)  
		return NULL;  
	slow = pHead;  //慢指针重新指向头节点
	while(slow != fast)  
	{  
		slow = slow->next;  
		fast = fast->next;  
	}  

	return slow;  
}

4. 单链表环长度

4.1 思想

快慢指针第一次相遇(超一圈)时开始计数,计数器累加,第二次相遇时停止计数
第二次相遇的时候快指针比慢指针正好又多走了一圈,也就是多走的距离等于环长

4.2 代码实现

//计算单链表环的长度  
int loopLength(pNode pHead)  
{  
	//首先通过上面的借口判断,链表是否有环
	if(isLoop(pHead) == false) 
	{
		return 0;  //没有环,则直接返回
	}
	pNode fast = pHead;  
	pNode slow = pHead;  
	int length = 0;  //环的长度
	bool begin = false;  //第一次相遇的 flag
	bool agian = false;  //第二次相遇的 flag
	while( fast != NULL && fast->next != NULL)  
	{  
		fast = fast->next->next;  
		slow = slow->next;  
		//超两圈后停止计数,挑出循环  
		if(fast == slow && agian == true)  
		{
			break;  
		}
		
		//超一圈后开始计数  
		if(fast == slow && agian == false)  
		{             
			begin = true;  
			agian = true;  
		}  
		
		//计数 +1  
		if(begin == true)  
		{
			++length;
		}
	}  
	
	return length;  
} 

5. 参考

http://www.cnblogs.com/xudong-bupt/p/3667729.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值