《剑指offer》:[37]如何得到链表环的入口地址

题目:如何得到链表环的入口结点
方案:分两步走:
第一步:先要找到链表中的环,得到环的结点的个数。可以设置两个指针一个走的比较快,一个比较慢,那么如果链表中存在一个环,那么这两个指针一定会陷入这个环中,快的指针一定会遇到慢的指针,所以很快就能遇到。 因为前面有详细讲过,这里不再多介绍,给一张图吧。
第二步:得到环的个数以后,我们照样可以设置两个指针。第一个指针先前进N(N为环中结点的个数)步,然后和第二个指针以相同的速度前进,当它们相遇时的结点就是链表中环的入口。

具体过程如下图所示:


具体实现代码如下所示:
#include <iostream>
using namespace std;
struct  List
{
	int data;
	List *next;
};
int arr[7]={1,2,3,4,5,6,7};
List *pHead=NULL;
List *pNext=NULL;
List *pEnd=NULL;
bool InputInvalid=false;
void Listhelp(List **head,int data)
{
	List *temp=new List ;
	temp->data=data;
	temp->next=NULL;
	if(NULL==*head)
	{
		*head=temp;
		pEnd=temp;
	}
	else
	{
		pEnd->next=temp;
		pEnd=temp;
	}	
}
void CreateList(List **head,int *array,int length)
{
	for(int i=0;i<length;i++)
		Listhelp(head,array[i]);
	//制造一个环;7->4
	List *temp=*head;
	while(temp->data!=4)
		temp=temp->next;
	pEnd->next=temp;
}
void show(List *head)
{
	int count=0;
	while(head)
	{
		cout<<head->data<<" ";
		head=head->next;
		count++;
		if(count==15)
			break;//有环所以用break退出;
	}
}
int GetNumOfCircle(List *head)
{
	int NodeCount=1;
	if(NULL==head)
	{
		InputInvalid=true;
		return 0;
	}
	List *pSlow=head->next;
	if(pSlow==NULL)
	{
		InputInvalid=true;
		return 0;
	}
	List *pFast=pSlow->next;// two steps;
	while(pSlow!=NULL && pFast!=NULL)
	{
		if(pFast==pSlow)
			break; //找到环;
		pSlow=pSlow->next;
		pFast=pFast->next;
		if(pFast!=NULL)
			pFast=pFast->next;
	}
	//计算环的个数;
	while(pFast->next!=pSlow)
	{
		pFast=pFast->next;
		NodeCount++;
	}
	return NodeCount;
}
//得到环的入口地址;
List *EntryNodeOfLoop(List *head,int count)
{
	List *pNode1=head;
	for(int i=0;i<count;i++)
		pNode1=pNode1->next;
	List *pNode2=head;
	while(pNode1!=pNode2)
	{
		pNode1=pNode1->next;
		pNode2=pNode2->next;
	}
	return pNode1;	
}
int main()
{
	int NodeCircle=0;
	List *EnterNode=NULL;
	CreateList(&pHead,arr,7);
	cout<<"有环4567:";
	show(pHead);
	cout<<endl;
	NodeCircle=GetNumOfCircle(pHead);
	if(InputInvalid)
		cout<<"THE INPUT IS INVALID@!"<<endl;
	else
	{
		EnterNode=EntryNodeOfLoop(pHead,NodeCircle);
		cout<<"环入口结点的值为:"<<EnterNode->data<<endl;
	}
	system("pause");
	return 0;
}

运行结果如下:











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值