1. 程式人生 > >3.6 程式設計判斷兩個連結串列是否相交

3.6 程式設計判斷兩個連結串列是否相交

(一)題目:輸入一個單項鍊表,找出該連結串列的倒數第k個節點。

   解法:設立兩個指標,先讓第一個指標先往前走k步,然後第二個指標放到連結串列開頭。

      然後兩個連結串列一起往後走,當第一個連結串列到達連結串列尾部的時候,後面那個連結串列所在的位置就剛好是連結串列的倒數第k個節點!

   程式碼:

struct node {
    int data;
    node *pNext;
};

node* funtion(node *head, int k) {
    assert(k >= 0);
    node *pOne, *pTwo;
    pOne = head;
    pTwo = head;
    for(; k >0 && pTwo != NULL; k--) {
        pTwo = pTwo->pNext;
    }
    if(k > 0) return NULL;
    while(pTwo != NULL) {
        pOne = pOne -> pNext;
        pTwo = pTwo -> pNext;
    }
    return pOne;
}

(二)題目:給定兩個單項鍊表,給定這兩個單項鍊表的頭指標,程式設計判斷這兩個連結串列是否相交。

   方法:因為兩個連結串列如果相交的話,那麼從相交節點開始,到最後,這兩個連結串列的後面的部分都是公共的部分!

     所以,只需要分別從兩個連結串列開頭,遍歷到最後結尾處,看看兩個尾部是不是相同的一個節點!如果是的話,說明這兩個連結串列是相交的,如果不是的話,說明這兩個     連結串列是不相交的。

   題目:上面說的這種方法是兩個連結串列都不帶環,但是如果連結串列帶了環呢!?

   所以總的方法:

(1)先判斷兩個連結串列帶不帶環

(2)如果都不帶環,就判斷兩個連結串列的尾節點是否相等。

(3)如果都帶環,判斷一連結串列上兩個指標相遇的那個節點,在不在另外一條連結串列上。如果在的話,則兩個連結串列相交。如果不在的話,則不相交。

   程式碼:

struct node {
    int data;
    node *pNext;
};

bool isCircle(node *head, node *&circleNode, node *&lastNode) {
    node *fast = head -> pNext;
    node *slow = head;
    while(fast && slow && fast != slow) {
        if(fast -> pNext != NULL)   fast = fast -> pNext;
        if(fast -> pNext == NULL)   lastNode = fast;
        if(slow -> pNext == NULL)   lastNode = slow;
        fast = fast -> pNext;
        slow = slow -> pNext;
    }
    if(fast == slow && fast && slow) {
        circleNode = fast;
        return true;
    } else return false;
}

bool detect(node *head1, node *head2) {
    node *circleNode1;
    node *circleNode2;
    node *lastNode1;
    node *lastNode2;
    
    bool isCircle1 = isCircle(head1, circleNode1, lastNode1);
    bool isCircle2 = isCircle(head2, circleNode2, lastNode2);
    
    if(isCircle1 != isCircle2) return false;        //兩個鏈變一個有環,一個無環
    else if(!isCircle1 && !isCircle2) return lastNode1 == lastNode2;        //兩個連結串列都無環
    else {              //兩個連結串列都有環
        node *temp = circleNode1 -> pNext;
        while(temp != circleNode1) {
            if(temp == circleNode2) return true;
            temp = temp -> pNext;
        }
        return false;
    }
    return false;
}


(三)求兩個連結串列相交的第一個節點

方法,思路:先求出更長的那個連結串列的,然後在這個連結串列上面先走長度之差的步數,然後兩個指標在一起走,走到最後,既是同一個節點!

struct node {
    int data;
    node *pNext;
};


unsigned int ListLength(node *pHead) {
    unsigned int nLength = 0;
    node *pNode = pHead;
    while(pNode != NULL) {
        nLength++;
        pNode = pNode -> pNext;
    }
    return nLength;
}


node* FindFirstCommonNode(node *pHead1, node *pHead2) {
    unsigned int nLength1 = ListLength(pHead1);
    unsigned int nLength2 = ListLength(pHead2);
    int nLengthDiff = nLength1 - nLength2;
    node *pListHeadLong = pHead1;
    node *pListHeadShort = pHead2;
    if(nLength1 < nLength2) {
        nLengthDiff = nLength2 - nLength1;
        pListHeadLong = pHead2;
        pListHeadShort = pHead1;
    }
    for(int i = 0; i < nLengthDiff; ++i) pListHeadLong = pListHeadLong -> pNext;
    while(pListHeadLong != NULL && pListHeadShort != NULL && pListHeadLong != pListHeadShort) {
        pListHeadLong = pListHeadLong -> pNext;
        pListHeadShort = pListHeadShort -> pNext;
    }
    node *pFirstCommonNode = NULL;
    if(pListHeadLong == pListHeadShort) pFirstCommonNode = pListHeadLong;
    return pFirstCommonNode;
}