1.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表不帶環)
兩個鏈表均不含有環,鏈表相交如下圖
解法一、直接法
直接判斷第一個鏈表的每個結點是否在第二個鏈表中,時間複雜度爲O(len1*len2),耗時很大。
解法二、利用計數
如果兩個鏈表相交,則兩個鏈表就會有共同的結點;而結點地址又是結點唯一標識。因而判斷兩個鏈表中是否存在地址一致的節點,就可以知道是否相交了。可以對第一 個鏈表的節點地址進行hash排序,建立hash表,然後針對第二個鏈表的每個節點的地址查詢hash表,如果它在hash表中出現,則說明兩個鏈表有共同的結點。這個方法的時間複雜度爲:O(max(len1+len2);但同時還得增加O(len1)的存儲空間存儲哈希表。這樣減少了時間複雜度,增加了存儲空間。
解法三、
兩個沒有環的鏈表相交於一節點,則在這個節點之後的所有結點都是兩個鏈表所共有的。如果它們相交,則最後一個結點一定是共有的,則只需要判斷最後一個結點是否相同即可。時間複雜度爲O(len1+len2)。對於相交的第一個結點,則可求出兩個鏈表的長度,然後用長的減去短的得到一個差值 K,然後讓長的鏈表先遍歷K個結點,然後兩個鏈表再開始比較。還可以這樣:其中一個鏈表首尾相連,檢測另外一個鏈表是否存在環,如果存在,則兩個鏈表相交,而檢測出來的依賴環入口即爲相交的第一個
#include<iostream>
#include<malloc.h>
#include<stdlib.h>
#define ERROR 0
using namespace std;
struct LinkList//鏈表結構體
{
int m_nValue;
LinkList *next;
};
void InsertList(LinkList *&list)//建立一個鏈表
{
LinkList *head;
LinkList *newNode;
int data;
head=list;
while(head->next)
head=head->next;
while(1)//鏈尾法構造鏈表
{
cin>>data;
if(data==0)break;
newNode=(LinkList *)malloc(sizeof(LinkList));
if(!newNode)exit(ERROR);
newNode->m_nValue=data;
newNode->next=NULL;
head->next=newNode;
head=newNode;
head->next=NULL;
}
}
void Traverse(LinkList *list)//輸出鏈表
{
LinkList *p;
p=list->next;
while(p)
{
cout<<" "<<p->m_nValue<<" address= "<<p<<endl;
p=p->next;
}
}
int main()
{
LinkList *first,*second;
LinkList *fhead,*shead,*h1,*h2,*p,*q;
int flen=0,slen=0,len;
first=(LinkList *)malloc(sizeof(LinkList));
first->next=NULL;
second=(LinkList *)malloc(sizeof(LinkList));
second->next=NULL;
InsertList(first);//構造第一個鏈表
cout<<endl;
InsertList(second);//構造第二個鏈表
/////////////////////////////////////////////////
//將第一個鏈表中從第四個結點起鏈接到第二個鏈表,構造兩個相交的鏈表
p=second;
while(p->next)
p=p->next;//找到第二個鏈表的尾結點
q=first;
for(int i=0;i<4;i++)
q=q->next;//找到第一個鏈表的第四個結點
p->next=q;//插入到第二個鏈表中
//////////////////////////////////////////////////
Traverse(first);
cout<<endl;
Traverse(second);
cout<<endl;
h1=first->next;
fhead=first;
while(fhead->next)//遍歷鏈表到表尾 (執行length1次,記n2次)
{
fhead=fhead->next;
flen++;
}
h2=second->next;
shead=second;
while(shead->next)//遍歷鏈表到表尾, (執行length2次,記n1次)
{
shead=shead->next;
slen++;
}
if(fhead==shead)//最後一個結點的地址相同,則相交
{
cout<<"兩鏈表相交"<<endl;
if(flen>=slen)//求兩個鏈表長度的差值
{
len=flen-slen;
while(len--) //遍歷差值個步長 (執行abs(length1-length2)次)
h1=h1->next;
}
else
{
len=slen-flen;
while(len--)
h2=h2->next;
}
while(1)
{
if(h1==h2)//兩個鏈表中地址相同的結點 (最多執行的次數爲:min(length1,length2))
{
cout<<"第一個相交的結點:"<<h1->m_nValue;
break;
}
else if(h1->next&&h2->next)
{
h1=h1->next;
h2=h2->next;
}
}
}
else
cout<<"兩鏈表不相交"<<endl;
}
1 2 3 4 5 6 7 8 0
99 78 3 0
1 address= 005E8260
2 address= 005E83F0
3 address= 005E8428
4 address= 005E8460
5 address= 005E8498
6 address= 005E8600
7 address= 005E8638
8 address= 005E8778
99 address= 005E8708
78 address= 005E8740
3 address= 005E8890
4 address= 005E8460
5 address= 005E8498
6 address= 005E8600
7 address= 005E8638
8 address= 005E8778
兩鏈表相交
第一個相交的結點:4請按任意鍵繼續…
2.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)【升級版】
鏈表中含有環,鏈表中有環如下圖:
則題目轉換爲鏈表帶環的判斷,參考鏈接:
http://blog.csdn.net/gaoruxue918/article/details/75208735
當兩個鏈表中有環時,相交的判斷:
(1)首先分別找出兩個鏈表入環的第一個結點記爲p1,p2
(2)如果p1==p2,說明兩個鏈表在入環之前或入環的第一個結點相交;則此時可以轉爲兩個鏈表均不帶環相交的判斷,把p1,p2當作最後的末尾結點
(3)如果p1!=p2,此時兩個鏈表可能完全不相交;也可能兩個鏈表完全共有同一個環。
此時,判斷p1->next與p2->next是否相等,如果相等則兩鏈表完全共環;如果不相等,則完全不相交。
當一個鏈表中有環,一個鏈表中沒有環時,兩個鏈表必不相交。