檢測鏈表是否有環,並且找到環的入口


第一步:檢測鏈表是否有環。

方法還是比較多的,這里先講一個:快慢指針。

快慢指針的方法,就是讓兩個指針同時指向鏈表。在向后遍歷的時候,一個指針每次走兩步,稱為快指針;一個指針每次走一步,稱為慢指針。如果快慢指針相遇,則說明鏈表有環,否則無環。(后面證明。)

代碼實現如下:

// 如果有環,則返回快慢指針相遇點。如果沒環,則返回NULL。
position
IsLoop(list l)
{
    if (l == NULL) {
        printf("Invalid parameter for function IsLoop!\n");
        exit(-1);
    }

    list fast, slow;
    fast = slow = l;
    
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        
        if (slow == fast)
            return slow;
    }

    return NULL;
}

 第二步:找到環的入口。

先畫張圖吧:

這是個有環的鏈表。

鏈表開頭與環的入口的距離為a,快慢指針相遇的地點距離環的入口為b,環的長度(節點的數量)為c。

那么我們可以知道,當快慢指針相遇的時候,快指針走的路程是慢指針的2倍。如果相遇的時候慢指針在環中走了m圈,快指針在環中已經走了n圈,那么必有n/m >= 2。

所以我們可以知道,相遇時,慢指針走的距離s1是a+mc+b,快指針走的距離s2是a+nc+b。

根據2*s1 = s2,我們有2(a+mc+b) = a+nc+b。

即a = (n-2m)c-b

n-2m是一個非負的常數。

(1)如果n-2m=0,又因為a和b也非負,所以a和b皆為0。意味着相遇點和入口重合,是鏈表的第一個結點。即環的入口就是鏈表的第一個結點。

(2)如果n-2m>0,設為N。則a=Nc-b=(N-1)c + c-b,這個式子意味着從鏈表開頭到環的入口的距離,等於從相遇點到入口的距離。而這個結論在(1)中的特殊情況也適用。

 

如果編程解決的話,就是讓兩個普通的指針(慢指針),一個指向鏈表的開頭,一個指向相遇點,然后開始往后走,直到它們相遇。而相遇點就是環的入口。

 


免責聲明!

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



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