如何判斷兩個單向鏈表是否有相交,並找出交點


轉載:http://blog.chinaunix.net/uid-20754793-id-177773.html

 

判斷兩個鏈表是否相交:(假設兩個鏈表都沒有環)
1、判斷第一個鏈表的每個節點是否在第二個鏈表中
2、把第二個鏈表連接到第一個后面,判斷得到的鏈表是否有環,有環則相交
3、先遍歷第一個鏈表,記住最后一個節點,再遍歷第二個鏈表,得到最后一個節點時和第一個鏈表的最后一個節點做比較,如果相同,則相交

如何判斷一個單鏈表是有環的?(注意不能用標志位,最多只能用兩個額外指針)
一種O(n)的辦法就是(用兩個指針,一個每次遞增一步,一個每次遞增兩步,如果有環的話兩者必然重合,反之亦然):
bool check(const node* head)
{
    if(head==NULL) return false;
    node *low=head, *fast=head->next;
    while(fast!=NULL && fast->next!=NULL)
    {
        low=low->next;
        fast=fast->next->next;
        if(low==fast) return true;
    }
    return false;
}

擴展問題參考:http://hi.baidu.com/azuryy/blog/item/18e85b02ec34a4094bfb51de.html
擴展1:如果鏈表可能有環,則如何判斷兩個鏈表是否相交
思路:鏈表1 步長為1, 鏈表2步長為2 ,如果有環且相交則肯定相遇,否則不相交

list1 head: p1
list2 head: p2
while( p1 != p2 && p1 != NULL && p2 != NULL )
{

      p1 = p1->next;
      if ( p2->next )
         p2 = p2->next->next;
      else
         p2 = p2->next;
}
if ( p1 == p2 && p1 && p2) //相交
else //不相交

擴展2:求兩個鏈表相交的第一個節點
思路:在判斷是否相交的過程中要分別遍歷兩個鏈表,同時記錄下各自長度。

Node* step( Node* p, Node* q)
{
    if ( !p || !q ) return NULL;
    int pLen = 1;
    int qLen = 1;
    bool result = false;
    while( p->next )
    {
        pLen++, p = p->next;
    }
    while( q->next )
    {
        qLen++, q = q->next;
    }
    result = ( p == q );
    if ( result )
    {
        int steps = abs( pLen - qLen);
        Node* head = pLen > qLen ? p : q;
        while ( steps ) //對齊處理
        {
                head = head->next, steps--;
        }
        pLen > qLen ? p = head : q = head;
        while ( p != q )
        {
                p = p->next, q = q->next;
        }
        reutrn p;
    }
    return NULL;
}
下面轉載來源:
http://blog.chinaunix.net/u2/63031/showart_1003241.html

深信服一道筆試:如何判斷兩個單向鏈表是否有相交,並找出交點。

題比較簡單,單向鏈表有交點意思就是交點后的節點都是一樣的了。

NODE* FindNode(NODE* pHead1, NODE* pHead2)
{
    NODE* p1 = pHead1;
    NODE* p2 = pHead2;
    int i = 1, j = 1, k = 0, f = 0;

    if(pHead2 == NULL || pHead2 == NULL)
    {
        return NULL;
    }

    while(p1->next != NULL)
    {
        p1 = p1->next;
        i++;
    }

    while(p2->next != NULL)
    {
        p2 = p2->next;
        j++;
    }

    if(p1 != p2)
    {
        return NULL;
    }
    else
    {
        p1 = pHead1;                // 1
        p2 = pHead2;

        f = fabs(i, j);
        if(i > j)                    // 2
        {
            for(k=0; k<f; k++)
            {
                p1 = p1->next;
            }
            while(p1 != p2)
            {
                p1 = p1->next;
                p2 = p2->next;
            }
            return p1;
        }
        else
        {
            for(k=0; k<f; k++)
            {
                p2 = p2->next;
            }
            while(p1 != p2)
            {
                p1 = p1->next;
                p2 = p2->next;
            }
            return p1;
        }
    }
}

1,在第一次遍歷完鏈表后,進行第二次遍歷,需要把指針再次初始化;看見網上一些人給的例子沒有再次初始化顯然是錯誤的;再調用NULL的next不死才怪!

2,小優化。循環和判斷,把判斷放在外面;如果把i和j大小判斷放在里面的話就意味着循環多少次,判斷就執行多少次;當然這樣做的唯一不足就是代碼 多了點;還有for循環之前的對f的賦值,有的為了簡便直接放在for語句里面,不過同樣道理,放在for循環里面,就執行了n次的fabs;拿出來賦 值,只賦值一次就OK。

友情提示:養成寫高效代碼的習慣,不能圖簡便,覺得代碼越少就越牛!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM