有環單鏈表

2022-09-18 11:27:27 字數 1763 閱讀 4908

單鏈表中可能存在環, 那麼如何判斷單鏈表中是否有環呢?若單鏈表中存在環,怎麼樣確定環的位置?

如果乙個單鏈表中存在環,在遍歷鍊錶時,一旦進入環,就開始迴圈遍歷環上的節點。如果只用乙個指標來遍歷單鏈表,我們無法判斷單鏈表中是否存在環。用兩個指標就可以完成這個任務。

設有兩個指標p1,p2。初始時p1和p2均指向鍊錶的第乙個節點。在遍歷過程中,p1總是移向下乙個節點(向前移動1步),同時p2總是指向下乙個節點的後繼節點(向前移動兩步)。如果單鏈表中存在環,p2在遍歷過程中一定會與p1指向同乙個節點(這是乙個相遇問題,p2的速度是p1的兩倍,它們一定會在環上相遇);否則在遍歷過程中p2不可能與p1相遇。

圖1中展示了乙個有環單鏈表。環外有 n1 個節點,環上有 n2 個節點,環的入口節點是 x 。設 p2 和 p1 在 y 節點處相遇。將環上的節點從環的入口開始沿著鍊錶編號,編號為1, 2, …, n2。 設 y 節點的編號為 n3 。則有:

2 *(n1 + k1 * n2 + n3)= n1 + k2 * n2 + n3

其中k1,k2分別是在相遇之前p1,p2各自遍歷環的次數。

令 k = k2 - 2 * k1, k >= 1。於是,

n1 = k * n2 – n3 = (k - 1) * n2 + n2 – n3

這就暗示了,如果令p1指向鍊錶的第乙個節點,p2指向y節點,p1和p2每次移向下乙個節點遍歷鍊錶,它們會在x節點處相遇,即找到了環的入口。                                              

圖 1  有環單鏈表

利用陣列next來表示鍊錶,節點從0開始編號,next[i]代表i節點的下乙個節點,-1標識鍊錶的結尾。例如陣列表示鍊錶 0->1->2->3->4->5->-1,這個鍊錶中沒有環。陣列 表示鍊錶 0->1->2->4->5->6->4,是乙個有環的單鏈表。下面是找出鍊錶中環的位置演算法的c語言實現:

1 #include 2

3int find_circle(int next, int

n) else

12 } while (p1 !=p2);

13 p1 = 0;14

do while (p1 !=p2);

18return

p1;19}20

21int

main() ;

24int node = find_circle(next, sizeof(next) / sizeof(int

));25

if (node != -1

) else

30return0;

31 }

這個演算法可應用到另乙個問題上。 問題描述如下:

有 n 個整數, 這些整數的取值範圍為 [1, n-1], 由鴿巢原理可知至少有乙個整數出現了兩次。 要求找到乙個(只乙個)重複出現的數字。

如 中的 4 和中的 2, 3 均為重複出現的數字。

我們利用find_circle解決這個問題基於這樣乙個觀察,就是乙個滿足題目條件的陣列可以看做多個迴圈單鏈表, 這些鍊錶之間可能有公共節點, 我們從任何乙個節點開始遍歷鍊錶都可以找到乙個環。 從0節點開始遍歷,環的入口就是乙個重複出現的數字; 從其他節點開始遍歷則不一定能夠找到重複數字。(想一想,為什麼?)

如 可以看做兩個鍊錶 0->1->3->4->5->4, 2->2 

如 可以看做是 0->1->2->3->3, 4->2->3->3 

判斷單鏈表是否有環

1 如何判斷乙個鍊錶是不是這類鍊錶?2 如果鍊錶為存在環,如果找到環的入口點?解答 一 判斷鍊錶是否存在環,辦法為 設定兩個指標 fast,slow 初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入環,而slow後進入環,兩個指標必定相遇。當然,fas...

判斷單鏈表是否有環

鍊錶結構 struct list 1 判斷單鏈表是否有環 採用追趕法,設定兩個指標p和q,從煉表表頭開始,p每一步走兩個節點,q每一步走乙個節點,如果鍊錶有環則p和q必相遇。如下 判斷鍊錶是否有環,時間複雜度o n 空間複雜度o 1 list hasloopinlist list head else...

判斷單鏈表是否有環

1 如何判斷乙個鍊錶是不是這類鍊錶?2 如果鍊錶為存在環,如果找到環的入口點?解答 一 判斷鍊錶是否存在環,辦法為 設定兩個指標 fast,slow 初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入環,而slow後進入環,兩個指標必定相遇。當然,fas...