两个链表是否相交可分为以下几种情况
(1)两个链表都不带环,此时两个链表所对应的最后一个节点是相等的
(2)两个链表一个带环,一个不带环,两个链表一定不相交
(3)连个链表都带环,如果相交则可以分为以下三种情况
1)两个链表在环外相交, 此时链表1 和链表2 对应的环的入口地址是相等的
2)两个链表在换上相交,此时从一个环的入口地址出发,一定可以到达另一个环的入口
3)如果不是以上两种情况,则连个链表一定不相交
/*
*
*链表是否相交没有环
*
*/
int LinkListHasCrossWithCircle(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return 0;
}
LinkNode* cur1 = head1;
while(cur1 -> next != NULL)
{
cur1 = cur1 -> next;
}
LinkNode* cur2 = head2;
while(cur2 -> next != NULL)
{
cur2 = cur2 -> next;
}
if(cur1 == cur2)
{
return 1;
}
return 0;
}
/*
*
* 链表是否相交,不确定有没有环
*
*/
int LinkListHasCrossWithCircle2(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return 0;//两链表至少一个为空
}
LinkNode* circle1 = LinkListHasCircle(head1);
LinkNode* circle2 = LinkListHasCircle(head2);
//两个链表都不带环
if(circle1 == NULL && circle2 == NULL)
{
return LinkListHasCrossWithCircle(head1, head2);
}
//两链表都带环
else if(circle1 != NULL && circle2 != NULL)
{
//在环外相交
LinkNode* entry1 = LinkListGetCircleEntry(head1);
LinkNode* entry2 = LinkListGetCircleEntry(head2);
if(entry1 == entry2)
{
return 1;
}
//再换上相交
else if(entry1 != entry2)
{
LinkNode* cur1 = entry1;
//从一个环入口点出发可以到达另外一个环入口点,则证明相交
while(cur1 != entry2)
{
cur1 = cur1 -> next;
}
return 1;
}
//不是上述情况则没有相交
return 0;
}
//一个带环一个不带环,则一定不相交
else if( ( circle1 == NULL && circle2 != NULL )
|| (circle1 != NULL && circle2 == NULL))
{
return 0;
}
}
求换的交点和上述判断是否有环是一个思路,可以分为一下几种情况
(1)两个链表都不带环的情况下,先利用上面的函数判断出连个链表是否相交,再求出两个链表的长度 size1, size2,再将两个链表的长度做差(长的减短的)得到一个大于等于0 的数 offset,再让分别定义两个指针 cur1, cur2, 指向 head1, head2, 然后让长链表对应的 cur1(假定cur1所指的链表长) 先走 offset 步,cur2 不动,cur1 每走一步 offset 就减1, 等到 offset 等于 0 的时候这个时候就说明两个指针cur1, cur2 都相对于交点的距离相等, 这个时候让 cur1, cur2 一起向后走,当它们两个指针所对应的节点相同时, 此时这个相同的节点就是两个链表的交点
(2)当两个链表一个带环,一个不带环时, 此时链表一定不相交,直接返回空
(3)当两个链表都有环时,分为一下三种情况
1)两个链表在环外相交,此时的交点求法如图所示
2)连个链表在环上相交
3)如果不是以上两种,那么一定不相交
/*
*
*环的相交点不带环
*
*/
LinkNode* LinkListCrossPoint(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;//两链表至少一个为空
}
int len1 = LinkListSize(head1);
int len2 = LinkListSize(head2);
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
int offset = 0;
if(len1 > len2)
{
offset = len1 - len2;
for(; offset > 0; cur1 = cur1 -> next)
{
offset--;
}
}
else if(len2 > len1)
{
offset = len2 - len1;
for(; offset > 0; cur2 = cur2 -> next)
{
offset--;
}
}
for(; cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next)
{
;
}
return cur1;
}
/*
*
*环的相交点带环不带环不确定
*
*/
LinkNode* LinkListCrossPoint2(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;//两链表至少一个为空,一定不相交
}
LinkNode* entry1 = LinkListGetCircleEntry(head1);
LinkNode* entry2 = LinkListGetCircleEntry(head2);
//如果两个都不带环,直接用第一个版本
if(entry1 == NULL && entry2 == NULL)
{
return LinkListCrossPoint(head1, head2);
}
//如果一个带环,一个不带环,一定不相交
if(( entry1 == NULL && entry2 != NULL ) || ( entry1 != NULL && entry2 == NULL ))
{
return NULL;
}
//如果两个都有环
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
if(entry1 != NULL && entry2 != NULL)
{
//环外相交
if(entry1 == entry2)
{
LinkNode* end = entry1;
int size1 = 0;
int size2 = 0;
for(; cur1 != end; cur1 = cur1 -> next)
{
size1++;
}
size1 = size1 + 1;
for(; cur2 != end; cur2 = cur2 -> next)
{
size2++;
}
size2 = size2 + 1;
int offset = 0;
if(size1 > size2)
{
offset = size1 - size2;
for(cur1 = head1, cur2 = head2; offset > 0; offset--)
{
cur1 = cur1 -> next;
}
for(; cur1 != end && cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next)
{
;
}
return cur1;
}
else if(size2 > size1)
{
offset = size2 - size1;
for(cur1 = head1, cur2 = head2; offset > 0; offset--)
{
cur2 = cur2 -> next;
}
for(; cur1 != end && cur1 != cur2; cur1 = cur1 -> next, cur2 = cur2 -> next)
{
;
}
return cur1;
}
else//size1 = size2
{
for(cur1 = head1, cur2 = head2; cur1 != cur2 && cur1 != end && cur2 != end; cur1 = cur1 -> next, cur2 = cur2 -> next)
{
;
}
return cur1;
}
}
//环内相交,相交点就是入口
else if(entry1 != entry2)
{
LinkNode* cur = entry1;
for(; cur != entry2; cur = cur -> next)
{
;
}
return entry2;
cur = entry2;
for(; cur != entry1; cur = cur -> next)
{
;
}
return entry1;
}
//不是上述两种情况,则不相交
else
{
return NULL;
}
}
}
求交集就是分别定义两个指针 cur1, cur2,指向两个对应的链表的首元素, 然后将 cur1 和 cur2 所指的链表的 data 进行比较, 如果相等, 将这个结点插入到一个新链表中, 然后两个指针 cur1, cur2, 一起向后走一步,如果不相等, 就将 data 值小的那个指针向后移动, 而另外一个指针不动, 在进行比较,重复以上动作,直到 cur1 或者 cur2 两个中其中一个为空,则停止循环
LinkNode* LinkListUnionSet(LinkNode* head1, LinkNode* head2)
{
if(head1 == NULL || head2 == NULL)
{
return NULL;//两个链表至少有一个为空
}
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
LinkNode* new_head = NULL;
LinkNode* new_tail = NULL;
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 -> data < cur2 -> data)
{
cur1 = cur1 -> next;
}
else if(cur1 -> data > cur2 -> data)
{
cur2 = cur2 -> next;
}
else
{
if(new_head == NULL)
{
new_head = LinkNodeCreat(cur1 -> data);
new_tail = new_head;
}
else
{
new_tail -> next = LinkNodeCreat(cur1 -> data);
new_tail = new_tail -> next;
}
cur1 = cur1 -> next;
cur2 = cur2 -> next;
}
}
return new_head;
}
先看一下复杂链表的数据结构
typedef struct ComplexNode
{
LinkNodeType data;
struct ComplexNode* next;
struct ComplexNode* random;
}ComplexNode;
复杂链表中除了 data, next, 之外,还有一个 random, 它可能指向链表中的如何一个节点, 还可能指向空。
在进行复杂链表的拷贝时, 可以采用下面的方法, 先将复杂链表按照简单链表进行复制,将其复制到一个新链表中, 此时的新链表还是一个简单链表, 然后再遍历旧链表,求出每一个节点所对应的 random 相对于头节点的偏移量, 再遍历新链表, 根据所求得的偏移量确定新链表中的 random 的指针的指向。
/*
*
* 复杂链表的拷贝
*
*/
ComplexNode* ComplexCopy(ComplexNode* head)
{
if(head == NULL)
{
return NULL;//空链表
}
ComplexNode* cur = head;
ComplexNode* new_head = NULL;
ComplexNode* new_tail = NULL;
while(cur != NULL)
{
if(new_head == NULL)
{
new_head = head ;
new_tail = new_head;
}
else
{
new_tail -> next = cur;
new_tail = new_tail -> next;
}
cur = cur -> next;
}
//求每个random相对于头结点的偏移量
int offset = 0;
ComplexNode* new_cur = new_head;
for(cur = head; cur != NULL; cur = cur -> next,new_cur = new_cur -> next)
{
//求出每个结点相对于head的偏移量
offset = Diff(head, cur -> random);
//修改新链表中的random的值
new_cur -> random = Step(new_head, offset);
}
return new_head;
}
/*
*
* 通过offset找到random
*
*/
ComplexNode* Step(ComplexNode* head, int offset)
{
if(head == NULL)
{
return NULL;//空链表
}
if(offset == -1)
{
return NULL;
}
ComplexNode* cur = head;
ComplexNode* random = head;
//让 random 走 offset 步,再将 cur -> random = random
for(; offset > 0; offset --)
{
random = random -> next;
}
return random;
}
/*
*
* 求出每个结点相对于head的偏移量
*
*/
int Diff(ComplexNode* head, ComplexNode* random)
{
if(head == NULL)
{
return -2;
}
if(random == NULL)
{
return -1;
}
ComplexNode* cur = head;
ComplexNode* new_cur = random;
int count = 0;
while(cur != new_cur)
{
count++;
cur = cur -> next;
}
return count;
}