1. 程式人生 > >兩個連結串列是否相交

兩個連結串列是否相交

判斷單鏈表中是否有環,找到環的入口節點:在MeetingNode方法中,當快慢指標(slow、fast)相遇時,slow指標肯定沒有遍歷完連結串列,而fast指標已經在環內迴圈了n(n>=1)圈。假設slow指標走了s步,則fast指標走了2s步。同時,fast指標的步數還等於s加上在環上多轉的n圈,設環長為r,則滿足如下關係表示式:

            2s = s + nr;

所以可知:s = nr;

假設連結串列的頭節點到“環的尾節點“的長度為L(注意,L不一定是連結串列長度),環的入口節點與相遇點的距離為x,連結串列的頭節點到環入口的距離為a,則滿足如下關係表示式:

            a + x = s = nr;

            可得:a + x = (n - 1)r + r = (n - 1)r + (L - a)

            進一步得:a = (n - 1)r + (L -a - x)

結論:

1> (L - a -x)為相遇點到環入口節點的距離,即從相遇點開始向前移動(L -a -x)步後,會再次到達環入口節點。

2> 從連結串列的頭節點到環入口節點的距離 = (n - 1) * 環內迴圈 + 相遇點到環入口點的距離。

3> 於是從連結串列頭與相遇點分別設一個指標,每次各走一步,兩個指標必定相遇,且相遇第一點為環入口點。

Node* EntryCircle(Node* head)

{

Node *slow = head, *fast = head;

while (fast && fast->next)

{

slow = slow->next;

fast = fast->next->next;

if (slow == fast)

{

while (head != slow)

{

head = head->next;

slow = slow->next;

}

return slow;

}

}

return NULL;

}

int GetLen(Node *head, Node *end)

{

int len = 0;

while (head != end)

{

head = head->next;

len++;

}

return len;

}

bool InSameCircle(Node* x, Node* y)

{

Node* next=x->next;

while(next!=x)

{

if(next==y) return true;

next=next->next;

}

return false;

}

Node* CrossNode(Node* x, Node* y)

{

if (x == NULL || y == NULL) return NULL;

Node* x1 = EntryCircle(x);

Node* y1 = EntryCircle(y);

if ((x1 != NULL && x1 == y1)

|| (x1 == NULL && y1 == NULL))

{

int len1 = GetLen(x, x1);

int len2 = GetLen(y, y1);

while (len1 > len2)

{

x = x->next;

len1--;

}

while (len2 > len1)

{

y = y->next;

len2--;

}

while (x)

{

if (x == y) return x;

x = x->next;

y = y->next;

}

}

else if(x1 != NULL && y1 != NULL && x1 != y1 && InSameCircle(x1, y1))

{

int len1 = GetLen(x, y1);

int len2 = GetLen(y, x1);

return (len1>len2?x1:y1);

}

return NULL;

}