判斷鍊錶中是否有環

2021-06-09 17:31:36 字數 1214 閱讀 1731

單向鍊錶中有環的話,如果我們對此鍊錶進行遍歷,則將無窮盡。因此有必要判斷乙個單向鍊錶是否有環。

假如乙個單向鍊錶中存在環,如下圖:(乙個小矩形代表鍊錶中的乙個節點)

虛線箭頭代表中間有無數節點。

先說演算法,然後再來證明演算法的正確性。

/*  鍊錶的頭指標為h  */

if((null == h) || (null == h->next)) /* 頭指標為空或者鍊錶中只有乙個節點,則無環,退出 */

return 0;

p = q = h; /* 設p和 q 指標, 均指向頭結點 */

while(1)

p = p->next;

q = (q->next)->next;

if((null == p) || (null == q))

printf(「no ringn」); /* 鍊錶中無環, 退出 */

return 0;

if(p == q) /* 鍊錶中有環 */

printf(「ring occurred/n」);

return 1;

可以看出,以上演算法設定了兩個指標p和q,他們分別以速度為1和2前進,如果到某一次迴圈發現他們相等,即都指向同一結點(空節點除外,以後討論的節點都不包含空節點),則說明這個單向鍊錶中存在迴圈。否則就是沒有迴圈。

我們注意到,指標p和q分別以速度為1和2前進。如果以其它速度前進是否可以呢?

下面我主要討論這個問題。

假設p和q分別以速度為v1和v2前進。如果有環,設指標p和q第一次進入環時,他們相對於環中第乙個節點的偏移位址分別為a和b(可以把偏移位址理解為節點個數)。如上圖。

這樣,可以看出,鍊錶有環的充要條件就是某一次迴圈時,指標p和

q的值相等,就是它們相對環中首節點的偏移量相等。

我們設環中的結點個數為n,程式迴圈了m次。

由此可以有下面等式成立:(mod(n)即對n取餘)

(a+m*v1)mod(n) = (b+m*v2) mod(n)

設等式左邊mod(n)的最大整數為k1,等式右邊mod(n)的最大整數為k2,則

(a+m*v1)-k1*n = (b+m*v2)-k2*n

m= |((k2-k1)*n+a-b)/( v2-v1)|       ①

如果是等式①成立,就要使迴圈次數m為一整數。顯然如果v2-v1為1,則等式成立。

這樣p和q分別以速度為v1和v2且|v2-v1|為1時,按以上演算法就可找出鍊錶中是否有環。

如何判斷鍊錶是否有環 鍊錶是否有環的判斷

對於鍊錶是否存在環,有三個問題需要考慮 1.是否有環 2.入環節點 3.環的長度 第一種方法快慢指標法,也稱之為龜兔演算法,設定兩個指標,慢指標和快指標。最開始均指向鍊錶的頭節點,之後,快指標每次後移兩個節點,慢指標每次後移乙個節點。1.如果快指標指向空,則鍊錶無環 2.若快指標和慢指標再次指向乙個...

判斷鍊錶是否有環

1.如何判斷是否有環?如果有兩個頭結點指標,乙個走的快,乙個走的慢,那麼若干步以後,快的指標總會超過慢的指標一圈。2.如何計算環的長度?第一次相遇 超一圈 時開始計數,第二次相遇時停止計數。3.如何判斷環的入口點 碰撞點p到連線點的距離 頭指標到連線點的距離,因此,分別從碰撞點 頭指標開始走,相遇的...

判斷鍊錶是否有環

單向鍊錶是最常用的資料結構之一,因此總結其常見的問題及其解決方案是很有意義的。問題1 如何判斷乙個單向鍊錶是否有環?如果有,如何找到其入口節點的指標?演算法思想 用兩個指標p1,p2同時指向鍊錶的頭部,p1一次移動一步,p2一次移動兩步,如果最終p1和p2重合則說明鍊錶有環,如果p2走到空指標 鍊錶...