連結串列中環的入口節點
阿新 • • 發佈:2019-01-22
題目:
一個連結串列中包含環,如何找出環的入口節點? 例如 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;
}