昨天做了乙個小總結,發現單鏈表這塊關於帶環鍊錶漏掉了,今天就來總結一下。
要尋找乙個單鏈表的環的入口點,首先得判斷乙個鍊錶是否帶環,那麼又怎樣判斷乙個單鏈表是否帶環呢?
首先我們得普及一下環有什麼特性,我們知道無環的單鏈表有首節點和尾節點,那麼帶環的單鏈表呢?顯然還是有首節點的,但是沒有尾節點吧。
如圖所示:
帶環的單鏈表既然沒有尾結點,那麼要是遍歷的話,就會無限迴圈,我們就沒法通過這樣來判斷這是帶環的,那麼我們就要想乙個辦法讓其停下來。
我們知道,運動會三千公尺賽跑的時候,第一名總會超過最後一名一圈,他們都是從同乙個起點開始跑的,最後跑的快的追上了跑的慢的。這就是圈的特性,那麼我們是不是也可以使用這一點來判斷單鏈表是否帶環。
我們定義乙個快的指標,讓其一步走兩個節點,再定義乙個慢的節點,一步走乙個節點,這樣,如果鍊錶帶環,那麼總有乙個地方讓這兩個指標是相遇的;如果不帶環那麼快的會先到尾結點。
那麼接下來就來實現吧:
typedef struct linknode //節點
linknode,*plinknode;
typedef struct linklist //鍊錶
linklist,*plinklist;
plinknode iscircle(plinklist plist) //判斷是不是帶環鍊錶
plinknode fast = plist->phead;
plinknode slow = plist->phead;
while (fast && fast->next) //如果快的指標先到尾結點,那麼不是。(奇偶)
return
null;
}
判斷是不是帶環的鍊錶很簡單,只要理解了這個過程,沒啥問題,那麼知道了鍊錶是帶環的鍊錶,如何來找帶環鍊錶的入口呢?
這涉及不太高深的數學問題,作為數學專業的我,還是很樂意講解的,首先來看下圖:
我們先將一些未知量設出來,這樣就可以進行運算了:
首先可以列出乙個簡單的等式:a+r=l ①
那麼再根據兩個指標來列乙個等式: a+n*r+x=(a+x)*2 ②
解釋一下第二個式子:左半部分是快的指標相遇前走的路程首先走了一段 a 之後,在進入環中走了 n 圈,又走了x段路程和慢的指標相遇;慢的指標路程因為它的速度是快的指標的一半,所以時間相同的情況下,快的指標走過的路程當然是慢的指標走過的路程的二倍。
然後聯合①、②得:a=n*r-x
這樣假設n為1時,即——a=r-x,我們要是再定義乙個指標,從表頭開始遍歷,同時,讓慢的指標從相遇點開始,那麼當他們相遇的時候,就是入口點的地方。
下面我們來看**:
plinknode firstcrossnode(plinklist plist)
plinknode ret = iscircle(plist); //接收相遇點的指標
if (ret ==
null)
plinknode start = plist->phead; //從表頭開始
plinknode slow = ret; //從相遇點開始
while (start)
}
單鏈表面試題系列之帶環鍊錶的入口點
本篇博文闡述如何找到帶環鍊錶的入口點,那麼,首先有必要闡述一下什麼是帶環鍊錶?如何判斷鍊錶是否帶環?帶環鍊錶 即鍊錶中有迴圈的部分,通俗的說就是沒有尾節點!例如 判斷鍊錶是否帶環 那麼知道了什麼是帶環鍊錶,接下來就是判斷鍊錶是否帶環的判斷問題了,其實也很簡單,首先最簡單的是判斷出不 帶環的鍊錶,只要...
單鏈表面試題 鍊錶帶環問題
判斷單鏈表是否帶環,並求得相遇點 思路 快慢指標問題,前面已經講過快慢指標原理,在這裡不再詳細描述 當快指標比慢指標多走一步,在某個環內一定會相遇在某一點 反過來則有 當兩個快慢指標在某一點相遇,這個鍊錶一定是帶環的鍊錶,反之不帶環 具體過程如圖 具體 鍊錶是否帶環 並返回相遇點 slistnode...
單鏈表 (面試題)
關於單鏈表的基本操作,之前已經總結過了,那些掌握之後算是了解了單鏈表是什麼?不過現在面試的題中,肯定不會只讓你回答單鏈表的基礎操作,總是會改變一些東西,或是擴充套件一下。下面就是一些關於單鏈表的擴充套件內容 include include include pragma warning disable...