若带环求环的长度?若带环求环的入口点?并计算以上每个问题的时间复杂度
求单链表是否存在环,环长,带环链表长
给定一个单链表,只给出头指针h:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
解法:
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。以下是个人证明,原博客的证明链接不中用了:
证:设连接点距离头指针为n,到相交点距离为x,圈长p,则2(n+x)=n+x+kp(k>0整数)必存在,转换后n=(k-1)p+(p-x),证明完毕
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
结点的定义:
typedef int DataType;
typedef struct Node
{
Node(const DataType& data)
: _pNext(NULL)
, _pPre(NULL)
, _data(data)
{}
Node* _pNext;
Node* _pPre;
int _data;
}Node, *pNode;
//1.判断链表是否带环
pair<pNode, bool> IsHaveCircle(pNode pHead)
{
assert(pHead);
pNode pfast = pHead;
pNode pslow = pHead;
while (pfast && pfast->_pNext)
{
pfast = pfast ->_pNext->_pNext;
pslow = pslow ->_pNext;
if (pfast == pslow)
return make_pair(pslow, true); //带环
}
return make_pair(pfast, false); //不带环
}
//2.若带环求环的长度
int sizeCircle(pNode pHead)
{
assert(pHead);
if (!IsHaveCircle(pHead).second)
return 0;
pNode Node = IsHaveCircle(pHead).first;
pNode pCur = Node->_pNext;
int count = 1;
while (pCur != Node)
{
count++;
pCur = pCur->_pNext;
}
return count;
}
//3.若带环求环的入口点
pNode FindCircle(pNode pHead)
{
assert(pHead);
pNode node = IsHaveCircle(pHead).first;
pNode pCur = pHead;
while (pCur != node)
{
pCur = pCur->_pNext;
node = node->_pNext;
}
return pCur;
}