求两个链表的公共节点可分为三步:
- 判断链表是否有环
采用传统的方法,两个指针同时指向头节点,p1一次走一步,p2一次走两步,如果p2走到终点还没有与p1相遇,那么无环,记录下链表的长度并返回空指针。这里要注意的是,p2由于一次走两步,有可能会出现“求null->next”的情况,需要再条件判断中避免。
如果p1和p2在某个地方相遇了,那相遇的这个地方一定在环上。可以画一个图,形状类似一只勺子。
从相遇的点和头结点同时开始遍历,这次相遇的点就是环的第一个节点,遍历的长度也就是不在环内的节点的个数。 - 判断是否可能存在交点
头结点相等的单列出来,此时不需要做其他工作,直接返回头结点。
不可能存在交点的情况要先排除:
1)存在空链表;
2)一个有环一个没有环;
所以可能有公共交点的链表需要满足:两个都无环,或者两个都有环。 - 求交点
1)当两个都无环或者都不是纯环时,需要求的公共交点一定不在环上。
2)两个都有环的话,排除头结点相等和都不是纯环的情况,即至少有一个是纯环,那么所求的第一个公共交点要么不存在,要么就是纯环的头结点。此时只需要判断纯环的头结点有没有在另一个链表的环上即可。
#include <iostream>
using namespace std;
struct ListNode
{
int Data;
ListNode *next;
ListNode(int val) :
Data(val),next(nullptr){}
};
ListNode *CreateListNode(int val)
{
return new ListNode(val);
}
ListNode *Circle(ListNode *head, int &len, bool IsCircle)//判断链表是否有环
{
ListNode *p1 = head;
ListNode *p2 = head;
int step = 1;
while (p2!=nullptr&&p2->next != nullptr)
{
p1 = p1->next;
p2 = p2->next->next;
step += 2;
if (p1 == p2)
break;
}
if (p2 == nullptr)//无环
{
len = step-1;
return nullptr;
}
else if (p2->next == nullptr&&p1 != p2)
{
len = step;
return nullptr;
}
else
{
IsCircle = true;
p1 = head;
step = 1;
while (p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
step++;
}
len = step;
return p1;
}
}
ListNode *InserPoint(ListNode *head1, ListNode *head2)
{
if (head1 == nullptr || head2 == nullptr)//有空链表的情况
return nullptr;
if (head1 == head2)//从头结点开始相等的情况
return head1;
int len1 = 0, len2 = 0;
bool IsCircle1 = false, IsCircle2 = false;
ListNode *CirclePoint1 = Circle(head1, len1, IsCircle1);//分别判断两链表是否有环
ListNode *CirclePoint2 = Circle(head2, len2, IsCircle2);
if (len1 > 0 && len2 > 0)//俩都没环或都有环并且不是头结点
{
int dif = len1 > len2 ? len1 - len2 : len2 - len1;
ListNode *h1 = len1 > len2 ? head2 : head1;
ListNode *h2 = len1 > len2 ? head1 : head2;
for (int i = 0; i < dif; i++)
{
h2 = h2->next;
}
while (h1 != h2)
{
h1++;
h2++;
}
return h1;
}
else if (len1 ==0||len2 == 0)//有一个纯环
{
ListNode *h1 = len1 > 0 ? head2 : head1;//取纯环的头结点
ListNode *h2 = len1 > 0 ? head1 : head2;
int len = len1 > 0 ? len1 : len2;
h2 += len;
ListNode *k = h2;
while (k->next!=h2)
{
k++;
if (h1 == k)
return h1;
}
return nullptr;//没有找到 则不相交
}
else//一个有一个没有 则不相交
return nullptr;
}
int main()
{
ListNode *h1 = CreateListNode(0);
ListNode *p = h1;
for (int i = 1; i < 6; i++)
{
ListNode *k = CreateListNode(i);
p->next = k;
p = p->next;
}
ListNode *h2 = h1->next;
ListNode *inser = InserPoint(h1, h2);
cout << inser->Data << endl;
return 0;
}
代码可能不完善,欢迎指正。