標籤:鏈表 相交 資料結構 無環 演算法
從此篇博文開始,講解一道古老的鏈表相交問題,共五篇
題目
給出倆個單向鏈表的頭指標,比如 h1,h2,判斷這倆個鏈表是否相交
解題步驟
- 判斷兩個【無環】鏈表是否相交
- 找到兩個【無環】鏈表的相交結點
- 判斷鏈表是否帶環
- 判斷兩個【有環】鏈表是否相交
- 找到兩個【有環】鏈表的相交結點
此篇先從最簡單的判斷兩個【無環】鏈表是否相交開始,順便介紹一下鏈表的基礎知識,方便一些對鏈表不太瞭解的同學學習。
基礎知識
什麼是鏈表?鏈表是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過鏈表中的指標連結次序實現的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態產生。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。
——From BaiKe畫個圖展示一下鏈表
資料結構如下
struct ListNode{int data;ListNode * nextNode;ListNode(ListNode * node,int value){nextNode=node;data=value;}};
有環鏈表?只需修改一下指標的指向,就會發現,這個鏈表永遠不會走到盡頭,如下
如何判斷兩個鏈表是否相交?思路:只要有一個節點相同,那麼兩鏈表就相交
方法一: 遍曆遍曆遍曆鏈表一,每次遍曆到鏈表一的一個節點時判斷是否和鏈表二的節點相同(方法同樣是遍曆),有相同的則說明兩鏈表相交。此方法當然可行,可是時間複雜度=O(length1*length2)
方法二:雜湊表法
既然連個鏈表一旦相交,相交節點一定有相同的記憶體位址,而不同的節點記憶體位址一定是不同的,那麼不妨利用記憶體位址建立雜湊表,如此通過判斷兩個鏈表中是否存在記憶體位址相同的節點判斷兩個鏈表是否相交。具體做法是:遍曆第一個鏈表,並利用地址建立雜湊表,遍曆第二個鏈表,看看地址雜湊值是否和第一個表中的節點地址值有相同即可判斷兩個鏈表是否相交。
時間複雜度O(length1 + length2)
空間複雜度O(length1) 因為需要建立大小為length1的雜湊表
分析:時間複雜度是線性,可以接受,並且可以順便找到第一個相交節點,但是卻增加了O(length1)的空間複雜度,這顯然不能令人滿意。——ref:http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/06/2580026.html
方法三:比較尾結點
只要兩鏈表相交,那麼相交後的那一段肯定是一樣的,也就意味著尾結點是一樣的
時間複雜度O(length1 + length2)
空間複雜度O(0)
尋找尾結點的函數,很簡單,就不解釋了
/**尋找尾結點*/ListNode * getLastNode(ListNode * head){if(head==NULL)return NULL;while(head->nextNode!=NULL){head=head->nextNode;}return head;}
原始碼
#include <stdio.h>#include<stdlib.h>#include <iostream>using namespace std;/**1.判斷兩個【無環】鏈表是否相交思路判斷尾節點是否相等*//**鏈表結構體*/struct ListNode{int data;ListNode * nextNode;ListNode(ListNode * node,int value){nextNode=node;data=value;}};ListNode * L1;ListNode * L2;//遍曆鏈表void ScanList(ListNode * node){while(NULL!=node){cout<<node->data<<endl;node = node->nextNode;}}/**尋找尾結點*/ListNode * getLastNode(ListNode * head){if(head==NULL)return NULL;while(head->nextNode!=NULL){head=head->nextNode;}return head;}//測試無環相交void testCross(){ListNode * node = new ListNode(NULL,0);node = new ListNode(node,1);node = new ListNode(node,2);L1 = new ListNode(node,11);L1 = new ListNode(L1,12);L1 = new ListNode(L1,13);L2 = new ListNode(node,21);L2 = new ListNode(L2,22);L2 = new ListNode(L2,23);}//測試無環不相交void testNotCross(){L1 = new ListNode(NULL,11);L1 = new ListNode(L1,12);L1 = new ListNode(L1,13);L2 = new ListNode(NULL,21);L2 = new ListNode(L2,22);L2 = new ListNode(L2,23);}void main(){testCross();//testNotCross();ListNode * node1 = getLastNode(L1);ListNode * node2 = getLastNode(L2);if(node1==node2)cout<<"相交"<<endl;elsecout<<"不相交"<<endl;system("pause");}
既然知道兩個【無環】鏈表相交,那麼怎麼找到相交結點,下一節,聊聊這個。
C語言強化(七)鏈表相交問題_1 判斷無環鏈表相交