鏈表相交問題【每日一題】

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是否相等,如果相等則兩鏈表完全共環;如果不相等,則完全不相交。

當一個鏈表中有環,一個鏈表中沒有環時,兩個鏈表必不相交。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章