#include<iostream>
using namespace std;
struct ListNode
{
int value;
struct ListNode * next;
ListNode(int v = 0) :value(v), next(nullptr){}
};
//判斷是否有環,如果有環,返回環內節點;如果沒有環,則返回nullptr
ListNode * IsLoop(ListNode * head)
{
if (head == nullptr || head->next == nullptr)
return nullptr;
ListNode * slow = head;
ListNode* fast = head->next;
while (fast!=nullptr&&slow!=fast)
{
slow = slow->next;
fast = fast->next;
if (fast != nullptr)
{
fast = fast->next;
}
}
return fast;
}
//計算環內長度
int LoopLenght(ListNode * head)
{
ListNode * stop = head;
head = head->next;
int count = 1;
while (head!=stop)
{
count++;
head = head->next;
}
return count;
}
//獲得環的入口結點
ListNode* EntryLoop(ListNode * head,int length)
{
if (head==nullptr || length==0)
{
return nullptr;
}
ListNode * slow=head;
ListNode * fast = head;
for (int i = 0; i <length; i++)
{
fast = fast->next;
}
while (slow!=fast)
{
slow = slow->next;
fast = fast->next;
}
return fast;
}
//計算帶環,鏈表長度
int List_length(ListNode * head, ListNode * end,int loop)
{
int count = 0;
while (head!=end)
{
count++;
head = head->next;
}
return count+loop;
}
ListNode * ListMeet(ListNode* head1, ListNode * head2, int len1, int len2)
{
if (len1<len2)
{
swap(head1, head2);
}
int k = abs(len1 - len2);
while (k--)
{
head1 = head1->next;
}
while (head1 != head2)//nullptr時相等
{
head1 = head1->next;
head2 = head2->next;
}
return head1;
}
bool TwoListMeet(ListNode * head1, ListNode* head2)
{
ListNode* isloop1= IsLoop(head1);
ListNode* isloop2 = IsLoop(head2);
//一個有環,一個無環,則必不存在交點
if ((isloop1==nullptr)^(isloop2==nullptr))
{
return false;
}
//兩個鏈表都沒有環
if ((isloop1 == nullptr) &&(isloop2 == nullptr))
{
int len1 = List_length(head1, nullptr, 0);//計算不帶環鏈表長度
int len2 = List_length(head2, nullptr, 0);
if(ListMeet(head1,head2,len1,len2)==nullptr)//可以保存meet節點
return false;
else
return true;
}
//兩個鏈表都有環時
//環內長度
int looplenght1=LoopLenght(isloop1);
int looplenght2 = LoopLenght(isloop2);
//獲得環的入口結點
ListNode* entry1 = EntryLoop(head1, looplenght1);
ListNode* entry2 = EntryLoop(head2, looplenght2);
//環外相遇
if (entry1==entry2)
{
//尋找相遇結點
int listlenght1 = List_length(head1, entry1, looplenght1);//計算帶環鏈表長度
int listlenght2 = List_length(head2, entry2, looplenght2);
ListNode* meet=ListMeet(head1, head2, listlenght1, listlenght2);//計算相遇節點
return true;
}
else
{
//判斷是否在環內相遇
ListNode * temp = entry1;
temp = temp->next;
while (temp!=entry1&&temp!=entry2)
{
temp = temp->next;
}
if (temp == entry2)
return true;
else
return false;
}
return false;
}
int main()
{
ListNode * node1 = new ListNode(1);
ListNode * node2 = new ListNode(2);
ListNode * node3 = new ListNode(3);
ListNode * node4 = new ListNode(4);
ListNode * node5 = new ListNode(5);
ListNode * node6 = new ListNode(6);
ListNode * node7 = new ListNode(7);
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node1;
node5->next = node6;
node6->next = node4;
node7->next = node6;
bool flag=TwoListMeet(node5, node7);
return 0;
}
代碼中如有不妥,歡迎指出!!
測試鏈表樣列:
樣列1:
樣列2: