给定一个单链表,只给出头指针h:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
解法:
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。(证明在后面附注)
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
void IsListLoop(Node *pHead,int *ListLength,int *LoopLength,int *junction)
{
if (NULL!=pHead || NULL!=ListLength || NULL!=LoopLength)
{
bool flag = false;
*ListLength = 0;*LoopLength = 0;*junction=0;
int lentghoutloop = 0;
Node *slow = pHead->next;
Node *fast = pHead->next;//指向第一个节点
Node *temp = NULL;
while (NULL!=fast && NULL!=fast->next)
{
slow = slow->next; //单步前进
fast = fast->next->next; //两步前进
if (slow == fast)
{
flag = true;
break;
}
}
if(flag)
{
cout<<"该链表有环"<<endl;
/*计算环的长度*/
temp = fast;
do
{
temp = temp->next;
++(*LoopLength);
} while (temp!=fast);//temp->next才开始计数,所以出循环后不需要--(*LoopLength)。
cout<<"LoopLength = "<<*LoopLength<<endl;
/*求取链接点,并计算环外长度*/
slow = pHead->next;
while (slow!=fast)
{
slow = slow->next;
fast = fast->next;
++lentghoutloop;
}
*ListLength = lentghoutloop + *LoopLength;//求取链表长度
cout<<"ListLength = "<<*ListLength<<endl;
*junction = slow->data;
cout<<"Junction Vaule = "<<*junction<<endl;
}
else
{
cout<<"该链表没有环"<<endl;
}
}
else
{
cout<<"输入参数有误!"<<endl;
}
}