1、判断链表是否带环
解析:这里可以用到追及的思维,设置两个快慢指针同时从头结点出发。如果链表带环,则快指针一定会追上满指针。
PNode HasCircle(PNode pHead)// 判断单链表是否带环
{
//快慢指针
PNode pFast = pHead;
PNode pSlow = pHead;
while (pFast && pSlow){
pFast = pFast->pNext->pNext;
pSlow = pSlow->pNext;
if (pFast == pSlow)
return pSlow;
}
return NULL;
}
2、求环的长度
解析:判断链表是否带环会得到一个快慢指针相遇的节点,从这个节点开始计数,走一圈就是环的长度。
size_t GetCircleLen(PNode pHead)// 求环的长度
{
PNode pMeetNode = HasCircle(pHead);
PNode pCur = NULL;
size_t len = 0;
if (pMeetNode == NULL)
return 0;
pCur = pMeetNode;
while (pCur->pNext!= pMeetNode){
len++;
pCur = pCur->pNext;
}
return len;
}
3、求环的入口点
如上图(y为环的周长):快慢指针走的时间相同,快指针走的路径是满指针的二倍,可得到
F = 2S
S=x+d
F=2 ( x + d ) = x + d + ny
得到:x = ny - d = (n-1)y + (y - d)(即表示从头结点到入口点和相遇点到入口点的距离一样)
PNode GetEnterNode(PNode pHead, PNode pMeetNode)// 求环的入口点
{
PNode pH = pHead;
PNode pM = pMeetNode;
if (pH == NULL || pM == NULL)
return NULL;
//到这步说明链表一定有环
while (pH != pM){
pH = pH->pNext;
pM = pM->pNext;
}
return pM;
}
4、判断两链表是否相交(假设链表不带环)
解析:仔细分析链表相交的情况,我们可以看到两链表最后的节点一定是相同的,否则它们就不想交。在这里直接遍历到尾结点,判断它们的尾结点是否相同。
//判断两个不带环链表是否相交(假设链表不带环)
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
PNode pTail1 = pHead1;
PNode pTail2 = pHead2;
while (pTail1)
pTail1 = pTail1->pNext;
while (pTail2)
pTail2 = pTail2->pNext;
return pTail1 == pTail2;
}
我在一些书上还看到另一种方法:把链表一的尾结点跟链表二的头结点链接起来构成环,若两链表相交则构成环。这样判断相交就变成了判断是否带环,求交点就变成了求环的入口点。
5、求交点
PNode GetCorssNode(PNode pHead1, PNode pHead2)//若相交求交点
{
size_t size1 = 0;
size_t size2 = 0;
PNode pCur1 = pHead1;
PNode pCur2 = pHead2;
int div = 0;
if (NULL == pHead1 || NULL == pHead2)
return NULL;
if (!IsCrossWithoutCircle(pHead1, pHead2))//不带环链表不相交
return 0;
while (pCur1)
{
size1++;
pCur1 = pCur1->pNext;
}
while (pCur2)
{
size2++;
pCur2 = pCur1->pNext;
}
div = size1 - size2;
if (div > 0)
{
while (div--)
pCur1 = pCur1->pNext;
}
else
{
while (div++)
pCur2 = pCur2->pNext;
}
while (pCur1 != pCur2)
{
pCur1 = pCur1->pNext;
pCur2 = pCur2->pNext;
}
return pCur1;
}