求有環鏈表(循環鏈表的第一個公共節點)

再次遇到,再次GG,雖然方法還記得,但是卻證明不出來!!可能這就是智商壓制吧。。。。天賦不夠,努力來湊。。。。

這個問題其實是分爲兩部分的
(1)判斷一個鏈表是不是有循環鏈存在。
我們可以設置兩個指針fast,flow.fast是每次向下移動兩個節點,low是每次向下移動一個節點。如果有循環鏈表他們必然會相遇。這個很好證明了。
首先如果如果有循環鏈表的話,這個兩個指針都會進入循環鏈,在循環鏈中fast跑得比low快一個節點單位,所以肯定會追上它,那就一定會出現兩個指針的值相等的情況。
代碼如下:


 bool if_exist(Node* head)
    {
        Node *fast,*low;
        fast=low=head;
        if(head==NULL||head->next==NULL||head->next->next==NULL)
            return false;
        while(fast!=NULL&&low!=NULL&&fast->next!=NULL)
        {
            fast=fast->next->next;
            low=low->next;
            if(fast==low)
               return true;
        }
        return false;
    }

沒什麼難的,接下來這個問題就有點難度了
(2)求循環鏈表的第一個公共節點,這個用到一部分上述結論,先說方法吧,我們找到那個公共節點後,將一個指針先指向頭結點,然後兩個指針一起向下走,每次都只走一個節點,這樣他們相遇的第一個節點就肯定是循環鏈的第一個公共節點!
這就需要嚴謹的數學證明了,今天就是想了半天沒證明出來。。。看來還是不夠學以致用啊
示意圖
設環的長度爲c(即m+l),
fast走的路程:s+c*round1+m
low走的路程:s+c*round2+m;
fast路程是low路程的兩倍,所以得出
s=c(2round1-round2)-m;
=c(2round1-round2-1)+c-m;
=c(2round1-round2-1)+I;
我們由此得到了起點到環入口點s和相遇點到環路口點I的等式關係。
這個等式關係就充分說明了當指針low鏈表頭開始,指針fast從相遇點開始,同時以一個步長往下走,必然會在第一個公共點相遇,當然,式子告訴我們可能fast先繞着環轉個幾圈再和low相遇。
代碼如下:

 Node* EntryNodeOfLoop(Node* head)
    {
        if(head==NULL|| head->next==NULL|| head->next->next==NULL)return NULL;
        Node *p,*q;
        p=q=pHead;
        while(p!=NULL&&q!=NULL)
        {
            p=p->next->next;
            q=q->next;
            if(p==q)
                break;
        }
        q=head;
        while(p!=q)
        {
            p=p->next;
            q=q->next;
        }
        return p;    
    }

真的啊,有時候不得不感慨數學的強大,其實不是很難證明,只是我們長期應對考試,用題海戰術,做題目的努力,卻有時候失去了自己獨立思考的能力。

不對。。。。是我,不是我們,在座的各位都是大佬。。。ORZ

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