题目:一个链表中包含环,如何找出环的入口结点?
例如,下图所示的链表中,环的入口结点就是结点3
完整测试程序:
#include <iostream>
using namespace std;
struct ListNode
{
int val;
ListNode* next;
};
//利用一快一慢两个指针,快指针速度是慢指针的两倍,找到两个指针在环中的相遇点
ListNode* MeetingNode(ListNode* pHead)
{
if (pHead == NULL) return NULL;
ListNode* fast = pHead;
ListNode* slow = pHead;
//如果无环,则fast先走到终点 ;当链表长度为奇数时,fast->Next为空 ;当链表长度为偶数时,fast为空
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow) //如果有环,则fast会超过slow一圈再相遇
{
return fast;
}
}
return NULL;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode = MeetingNode(pHead);
if (meetingNode == NULL)
return NULL;
// 求环中的节点个数
int nodesInLoop = 1;
ListNode* pNode1 = meetingNode;
while (pNode1->next != meetingNode)
{
pNode1 = pNode1->next;
++nodesInLoop;
}
// 结点指针pNode1先走nodesInLoop步
pNode1 = pHead;
for (int i = 0; i < nodesInLoop; ++i)
pNode1 = pNode1->next;
// 结点指针pNode1 和pNode2以相同的速度一起走
ListNode* pNode2 = pHead;
while (pNode1 != pNode2)
{
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pNode1;
}
ListNode* CreateListNode(int value)
{
ListNode* pNode = new ListNode();
pNode->val= value;
pNode->next = NULL;
return pNode;
}
void DestroyList(ListNode* pHead)
{
ListNode* pNode = pHead;
while (pNode != NULL)
{
pHead = pHead->next;
delete pNode;
pNode = pHead;
}
}
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
{
if (pCurrent == NULL)
{
printf("Error to connect two nodes.\n");
exit(1);
}
pCurrent->next = pNext;
}
int main()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
ConnectListNodes(pNode5, pNode3);
ListNode* res = EntryNodeOfLoop(pNode1);
cout << "链表中环的入口结点是:"<<res->val<<endl;
system("pause");
DestroyList(res);
return 0;
}
ps:参考《剑指offer》中面试题56:链表中环的入口结点