面试题56:链表中环的入口结点

题目:一个链表中包含环,如何找出环的入口结点?


首先,如果判断一个链表有环?

设置两个指针,一个指针一次走一步,一个指针一次走两步,如果链表有环,那么两个指针一定会相遇,而且是在环内相遇。


求环的入口结点:设置P1和P2两个指针指向头结点,如果环中有n个结点,指针P1现在链表上移动n步然后两个指针以相同的速度向前移动,当第二个指针指向环的入口点时,第一个指针已经围绕着环走了一圈,又回到了入口结点,即它们相遇的时候就是环的入口结点。


求环中结点个数:判断一个链表是否有环的时候,使用一快一慢两个指针,如果两个指针相遇则表明链表有环,两个指针相遇的结点一定是在环中,可以从这个结点出发,一边继续向前移动一边计数,当再次回到这个结点时,就可以得到环中结点数。


struct ListNode 
{
	int value;
	ListNode * next;
};

//如果链表有环,找到一快一慢两个指针相遇的一个结点
ListNode* MeetingNode(ListNode* pHead)
{
	if(pHead==NULL)
		return NULL;

	ListNode* pSlow=pHead->next;
	if(pSlow==NULL)
		return NULL;

	ListNode* pFast=pSlow->next;

	while(pFast!=NULL&&pSlow!=NULL)
	{
		if(pFast==pSlow)
			return pFast;

		pSlow=pSlow->next;

		//pFast一次走两步
		pFast=pFast->next;
		if(pFast->next!=NULL)
			pFast=pFast->next;
	}
	return NULL;
}

ListNode * EntryNodeOfLoop(ListNode * pHead)
{
	ListNode * meetingNode=MeetingNode(pHead);
	if(meetingNode==NULL)
		return NULL;

	//计算环中的结点数
	int nodesInLoop=1;
	ListNode* node1=meetingNode;
	while(node1->next!=meetingNode)
	{
		node1=node1->next;
		nodesInLoop++;
	}

	node1=pHead;//第一个指针指向头结点
	ListNode* node2=pHead;//第二个指针也指向头结点

	//先将node1走nodesInLoop步
	for(int i=0;i<nodesInLoop;i++)
	{
		node1=node1->next;
	}

	//两个指针同时走,相遇的时候就是入口结点
	while(node1!=node2)
	{
		node1=node1->next;
		node2=node2->next;
	}
	return node1;
}


延伸:

判断两个链表是否相交:http://www.cppblog.com/zengwei0771/articles/172700.html

1.当两个链表都没有环的时候,如果两个链表相交,那么尾结点一定相同,判断它们的尾结点是否相同。

2.一个链表有环,另一个链表无环,则它们一定不相交。

3.当两个链表都有环的时候,两个链表环的入口结点为P1和P2

1)如果P1=P2一定相交

2)P1不等于P2

   (1)P1不等于P2,判断它们是否在一个换,从P1开始向后遍历看是否能达到P2,如果能达到说明在一个环中,两个链表相交

   (2)P1不等于P2,并且不在一个环,两个链表不想交。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值