链表环和环入口点
0.单链表节点定义:
struct Node
{
int _val;
Node* next;
Node()
{
next = NULL;
}
Node(int val):_val(val),next(NULL){}
};
1.单链表翻转
用双指针, 一个指针指向当前节点, 一个指针指向当前节点的前一个节点, 用临时变量记录当前指针的next, 当前指针的next指向前一个节点, 前一个指针指向当前节点, 当前节点指针指向临时变量记录的节点。
void Reverse(Node* pHead)
{
Node* pPre = NULL;
Node* pCur = pHead;
Node* pTmp;
while(pCur != NULL)
{
pTmp = pCur->next;
pCur->next = pPre;
pPre = pCur;
pCur = pTmp;
}
pHead = pPre;
}
2.判断链表是否有环
用双指针, 一个指针一次走一步, 一个指针一次走两步, 如果指向同一块内存,则说明链表有环。
bool IsLoopList(Node* pHead)
{
Node* pSlow = pHead;
Node* pFast = pHead;
while(pFast != NULL && pFast->next != NULL)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
if(pSlow == pFast)
{
return true;
}
}
return false;
}
3.链表的环入口点
在2的基础上相遇后展开分析:
寻找入口点思路
快慢指针相遇后,假设慢指针经过k个节点,则快指针经过2k个节点, 从链表头到环入口经过x个节点,从环入口到相遇点经过y个节点,从相遇点继续走到到环入口结果z个节点(环的长度l = y+z)
x + y = z 慢指针
n(y+z) + x+y = 2k; 快指针, n > 0
则 n(y+z) = k
则 (n-1)(y+z) + y+z = k; => (n-1)(y+z) + y + z = x + y
=> (n-1)*(y+z) + z = x
所以从链表头经过x个节点 和 从相遇点经过 x个节点后两个指针又会相遇, 且相遇点是链表入口点
Node* GetLoopListEnterNode(Node* pHead)
{
Node* pSlow = pHead;
Node* pFast = pHead;
while(pFast != NULL && pFast->next != NULL)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
if(pSlow == pFast)
{
//寻找环入口
pSlow = pHead;
while(pSlow != pFast)
{
pSlow = pSlow->next;
pFast = pFast->next;
}
Node* loopEnterNode = pSlow;
return loopEnterNode;
}
}
return NULL;
}