链表中环的入口几点
题目:一个链表中包含环,如何找出环的入口结点?例如,在链表中, 环的入口结点是结点3。
分析:(1)首先我们要确定链表是否有环,可以考虑使用双指针来确定。定义两个指针,同时从链表的头部出发,第一个指针走一步,第二个指针一次走二步。如果走的快的指针追上了走的慢的指针,那么就证明链表有环。如果走的快的指针走到了链表的末尾(m_pnext指向NULL)都没有追上第一个指针,那么表示无环。
(2)找到环的入口。还是可以用2个指针来解决问题。先定义两个指针p1和p2指向链表的头结点,。如果链表环中有n个几点,那么p1指针先走n步,然后两个指针再以相同的速度往前走。直到相遇,则是入口节点。看图!!!
(3)如何确定环中节点数。再判断是否有环时用到了2个指针。两个指针相遇的节点一定在此环中。可以从这个节点出发,定义个pNode,然后一边走一边计数,当再次回到这个节点,即得到了环中的节点数。
代码:
//首先需要确定链表是否有环。即要确定两个指针相遇的节点
ListNode* MeetingNode(ListNode *phead)
{
if (phead == nullptr)
{
return nullptr;
}
ListNode* pSlow = phead->m_pNext; //慢指针一次走一步
if (pSlow == nullptr)
{
return nullptr;
}
ListNode* pFast = pSlow->m_pNext; //快指针比慢指针快走两步
while (pSlow != nullptr || pFast != nullptr)
{
if (pSlow = pFast)
{
return pFast; //当快指针追上了慢指针,则表示有环,且重合点即为相遇节点
}
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if (pFast != nullptr)
{
pFast = pFast->m_pNext;
}
}
return nullptr;
}
//找到环中的任意节点,即可以确定环中的节点数,然后找到入口节点
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode = MeetingNode(pHead);
if (meetingNode == nullptr)
{
return nullptr;
}
int count = 1;
ListNode* pNode1 = meetingNode;
//当从相遇节点,开始走,一边走一边计数,当再次回到相遇节点,即算出环中节点个数
while (pNode1->m_pNext != meetingNode)
{
pNode1 = pNode1->m_pNext;
count++;
}
//将pNode1放置头结点,然后移动环中节点数的次数,
pNode1 = pHead;
for (int i =0 ;i < count;i++ )
{
pNode1 = pNode1->m_pNext;
}
//第一个指针走完,第二指针和第一指针,开始正常走,直到相遇。则是入口节点,
ListNode* pNode2 = pHead;
while (pNode1 != pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}
测试用例
// ==================== Test Code ====================
void Test(const char *testname, ListNode* pHead, ListNode* expected)
{
if (testname != nullptr)
{
printf("%s begins\n", testname);
}
if (EntryNodeOfLoop(pHead) == expected)
{
printf("PASSED!!!!\n");
}
else
{
printf("Failed!!!\n");
}
}
//只有一个节点,没有环
void test1()
{
ListNode* pNode1 = CreateListNode(1);
Test("test1", pNode1, nullptr);
DestroyList(pNode1);
}
//只有一个节点,一个环
void test2()
{
ListNode* pNode1 = CreateListNode(1);
ConnectListNodes(pNode1, pNode1);
Test("TEST2", pNode1, pNode1);
delete pNode1;
pNode1 = nullptr;
}
//有多个节点,且有环
void test3()
{
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);
Test("Test3", pNode1, pNode3);
delete pNode1;
pNode1 = nullptr;
delete pNode2;
pNode2 = nullptr;
delete pNode3;
pNode3 = nullptr;
delete pNode4;
pNode4 = nullptr;
delete pNode5;
pNode5 = nullptr;
}
//有多个节点,且环点位于头结点
void test4()
{
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, pNode1);
Test("Test4", pNode1, pNode1);
delete pNode1;
pNode1 = nullptr;
delete pNode2;
pNode2 = nullptr;
delete pNode3;
pNode3 = nullptr;
delete pNode4;
pNode4 = nullptr;
delete pNode5;
pNode5 = nullptr;
}
有多个节点,且环点位于尾结点
// A list has multiple nodes, with a loop
void Test4()
{
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, pNode1);
Test("Test4", pNode1, pNode1);
delete pNode1;
pNode1 = nullptr;
delete pNode2;
pNode2 = nullptr;
delete pNode3;
pNode3 = nullptr;
delete pNode4;
pNode4 = nullptr;
delete pNode5;
pNode5 = nullptr;
}
// A list has multiple nodes, with a loop
void test5()
{
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, pNode5);
Test("Test5", pNode1, pNode5);
delete pNode1;
pNode1 = nullptr;
delete pNode2;
pNode2 = nullptr;
delete pNode3;
pNode3 = nullptr;
delete pNode4;
pNode4 = nullptr;
delete pNode5;
pNode5 = nullptr;
}
//多个节点,且无环
void test6()
{
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);
Test("Test6", pNode1, nullptr);
DestroyList(pNode1);
}
int main()
{
test1();
test2();
test3();
test4();
test5();
test6();
return 0;
}