1. 程式人生 > >連結串列中環的入口節點

連結串列中環的入口節點

題目:
一個連結串列中包含環,如何找出環的入口節點? 例如 1->2->3->4->5->6->(3) ; 的連結串列中,環的入口及誒到哪是節點 3。

解析:

  • 首先找到連結串列中的環:定義2個指標,一個快指標一次走2步,一個慢指標一次走1步,如果2個指標能夠相遇,證明有環。
  • 統計連結串列中環的長度:從相遇指標開始,固定 1 個指標,另一個指標從相遇指標走,當2個指標再次相遇時,即走了 1 圈,得到環的長度 len。
  • 2個指標指向連結串列開頭,1個指標先走 len 步,另一個指標從頭和前一個指標一起走,當 2 個指標相遇時,即是環的入口。
#include
<iostream> using namespace std; class Node { public: int val; Node* next; Node(int v, Node* n = NULL):val(v), next(n) {}; }; int GetCircleNodeNums(Node* pHead) { if (pHead == NULL) return 0; // 一快一慢,相遇時,則找到環 Node* pSlow = pHead; Node* pFast = pSlow->next; while
(pFast != NULL && pSlow != NULL) { if (pFast == pSlow) break; pSlow = pSlow->next; if (pFast->next) { pFast = pFast->next->next; } else { break; } } // 固定一個指標,一個指標走,再次相遇時,則是一圈,得到環長度 int counts =
0; // 如果 p1, p2 有一個為NULL,則不存在環,返回0 Node* p1 = pFast, *p2 = pSlow; if (p1 == p2 && p1 != NULL) { p1 = p1->next; counts++; while (p1 != p2) { p1 = p1->next; counts++; } } return counts; } Node* FindCircleEntrance(Node* pHead) { if (pHead == NULL) return NULL; int circle_len = GetCircleNodeNums(pHead); if (circle_len == 0) return NULL; // 沒有環 Node* p1 = pHead, *p2 = pHead; // p1 先走一個環的長度 while (circle_len) { p1 = p1->next; circle_len--; } // p1, p2 一起走,相遇時則是環的入口 while (p1 != p2) { p1 = p1->next; p2 = p2->next; } return p1; } int main() { // 1->2->3->4->5->6->(3) Node* pList = NULL; Node* pNode1 = new Node(1, NULL); Node* pNode2 = new Node(2, NULL); Node* pNode3 = new Node(3, NULL); Node* pNode4 = new Node(4, NULL); Node* pNode5 = new Node(5, NULL); Node* pNode6 = new Node(6, NULL); pNode1->next = pNode2; pNode2->next = pNode3; pNode3->next = pNode4; pNode4->next = pNode5; pNode5->next = pNode6; pNode6->next = pNode3; pList = pNode1; cout << "環的長度 :"<< GetCircleNodeNums(pList) << endl; Node* EntranceNode = FindCircleEntrance(pList); if (EntranceNode) cout << "環的入口節點的值:"<< EntranceNode->val << endl; }