由于单链表的特殊性,如果某一链表与另一链表相交,那么从相交的节点开始,以后两个链表的每个节点都相同,因此判断两个链表是否相交,只需判断每条链表的最后一个节点是否相同即可!
#include "stdafx.h"
#include <iostream>
using namespace std;
struct list_node
{
int data;
list_node* next;
};
list_node* CreateList(int datas[],int n)
{
if(n < 1) return NULL;
list_node* head = new list_node;
head->data = datas[0];
head->next = NULL;
list_node* p = head;
for (int i = 1; i < n; ++i)
{
list_node* new_node = new list_node;
new_node->data = datas[i];
new_node->next = NULL;
p->next = new_node;
p = new_node;
}
return head;
}
void DisplayList(list_node* head)
{
list_node* p = head;
while(p)
{
cout<<p->data<<‘ ‘;
p = p->next;
}
cout<<endl;
}
void FreeList(list_node* head)
{
while(head)
{
list_node* p = head->next;
delete head;
head = p;
}
}
bool IsInterseced(list_node* list1,list_node* list2)
{
list_node* p1 = list1,*p2 = list2;
while(p1->next)
{
p1 = p1->next;
}
while(p2->next)
{
p2 = p2->next;
}
return p1 == p2;
}
int _tmain(int argc, _TCHAR* argv[])
{
int datas[] = {3,2,0,3,6,8,34,23,9,5,4};
list_node* list1 = CreateList(datas,11);
list_node* list2 = CreateList(datas,7);
DisplayList(list1);
DisplayList(list2);
//两条链表没有相交时,可以安全释放每一条链表
//FreeList(list1);
//FreeList(list2);
cout<<IsInterseced(list1,list2)<<endl;
list_node* list2_tail = list2;
for (int i = 0; i < 6; ++i)
{
list2_tail = list2_tail->next;
}
//让第二个链表的最后一个节点的next指针指向第
//一个链表的第三个节点,如此则两个链表相交
list2_tail->next = list1->next->next;
cout<<IsInterseced(list1,list2)<<endl;
//两条链表相交时,安全释放每一条链表需要做更多的工作,
//否则,程序一定会崩溃
//...
return 0;
}
接下来,需要求取从哪一个节点开始相交。由于两个链表相交,要么两条链表的长度一样,要么一长一段(将公共部分也算入总长度中),所以我的思路是先将较长的哪一条链表从头开始跳过其比另一链表多出来的节点的个数,到达节点a,此时长链表如果从节点a算起,短链表从头算起,则两条链表的长度一样,这样,只需检查每个对应的节点是否相同,第一相同的节点即为开始相交的节点。修改IsInterSection函数如下:
bool IsInterseced(list_node* list1,list_node* list2,list_node** intersection_node)
{
*intersection_node = NULL;
if(list1 == NULL || list2 == NULL) return false;
list_node* p1 = list1,*p2 = list2;
int node_count1 = 1;
while(p1->next)
{
++node_count1;
p1 = p1->next;
}
int node_count2 = 1;
while(p2->next)
{
++ node_count2;
p2 = p2->next;
}
if(p1 != p2) return false;
int D_value = 0;
if(node_count1 >= node_count2)
{
p1 = list1;
p2 = list2;
D_value = node_count1 - node_count2;
}
else
{
p1 = list2;
p2 = list1;
D_value = node_count2 - node_count1;
}
for (int i = 0; i < D_value; ++i)
{
p1 = p1->next;
}
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
*intersection_node = p1;
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
int datas[] = {3,2,0,3,6,8,34,23,9,5,4};
list_node* list1 = CreateList(datas,11);
list_node* list2 = CreateList(datas,7);
DisplayList(list1);
DisplayList(list2);
//两条链表没有相交时,可以安全释放每一条链表
//FreeList(list1);
//FreeList(list2);
list_node* intersection_node = NULL;
cout<<IsInterseced(list1,list2,&intersection_node)<<endl;
list_node* list2_tail = list2;
for (int i = 0; i < 6; ++i)
{
list2_tail = list2_tail->next;
}
//让第二个链表的最后一个节点的next指针指向第
//一个链表的第三个节点,如此则两个链表相交
list2_tail->next = list1->next->next;
cout<<IsInterseced(list1,list2,&intersection_node)<<endl;
cout<<intersection_node->data<<endl;
//两条链表相交时,安全释放每一条链表需要做更多的工作,
//否则,程序一定会崩溃
//...
return 0;
}
从程序运行截图可以看到,相交的节点的数值是0,两个链表中只有一个0,且在第三个节点上,从而验证了算法。
如果已经知道了两条链表各自的长度,是否可以省去前面的两次对链表的遍历呢?不能,相交后两条链表长度的差值未必就是原来两条链表长度的差值,本例中原本的链表长度差值为4,而相交后差值为5.因此,在我看来,开始的两次遍历不可避免,整个算法的复杂度为O(m + n),m与n为原始链表的长度。
原文地址:http://blog.csdn.net/liao_jian/article/details/44498645