單向鍊錶當中的環路判別問題

2021-09-05 14:32:42 字數 1568 閱讀 6462

from:

有乙個單向鍊錶,如何判定這個鍊錶當中是否包含有環路,以及如何定位環路在鍊錶當中的開始點呢?

關於第乙個問題,網路上可以搜尋到,用兩個指標來遍歷這個單向鍊錶,第乙個指標p1,每次走一步;第二個指標p2,每次走兩步;  當p2 指標追上 p1的時候,就表明鍊錶當中有環路了。

關於這個解法最形象的比喻就是在操場當中跑步,速度快的會把速度慢的扣圈

可以證明,p2追趕上p1的時候,p1一定還沒有走完一遍環路,p2也不會跨越p1多圈才追上

我們可以從p2和p1的位置差距來證明,p2一定會趕上p1但是不會跳過p1的

因為p2每次走2步,而p1走一步,所以他們之間的差距是一步一步的縮小,4,3,2,1,0 到0的時候就重合了

根據這個方式,可以證明,p2每次走三步以上,並不總能加快檢測的速度,反而有可能判別不出有環

比如,在環的周長l是偶數的時候,初始p2和p1相差奇數的時候,p2每次走三步,就永遠和p1不重合,因為他們之間的差距是:  5, 3 , 1,  l-1, l-3

關於第二個問題,如何找到環路的入口,是這裡要重點說明的內容:

解法如下: 當p2按照每次2步,p1每次一步的方式走,發現p2和p1重合,確定了單向鍊錶有環路了

接下來,讓p2回到鍊錶的頭部,重新走,每次步長不是走2了,而是走1,那麼當p1和p2再次相遇的時候,就是環路的入口了。

這點可以證明的:

在p2和p1第一次相遇的時候,假定p1走了n步驟,環路的入口是在p步的時候經過的,那麼有

p1走的路徑: p+c = n;         c為p1和p2相交點,距離環路入口的距離

p2走的路徑: p+c+k*l = 2*n;   l為環路的周長,k是整數

顯然,如果從p+c點開始,p1再走n步驟的話,還可以回到p+c這個點

同時p2從頭開始走的話,經過n不,也會達到p+c這點

顯然在這個步驟當中p1和p2只有前p步驟走的路徑不同,所以當p1和p2再次重合的時候,必然是在鍊錶的環路入口點上。

測試**如下:

#include "iostream.h"

#include "memory.h"

#include "new.h"

class clist * proot = null;

const int size = sizeof(clist) / sizeof(int);

int  buffer[101*size];

bool init(int n)

;ptemp->pnext = (clist *) (buffer + n*size);

return true;}

void clearcircle(clist * proot)

while ( p2!=null && p1!=p2);

if ( p1 == p2 )

p1->pnext = null;}}

main()

clearcircle(proot);

}cout << "after clear:" << "\r\n";

plist = proot;

while (plist)

return 0;

}

單向鍊錶逆序問題

問題 將乙個單向單向鍊錶逆序倒轉,要求o n 的時間複雜度和o 1 的空間複雜度 該問題有兩種解法,一種非遞迴,一種是遞迴,如下 include include link.h typedef struct linknode linknode 遞迴 linknode reverselink linkn...

單向鍊錶的查詢問題

題目 輸入乙個單向鍊錶。如果該鍊錶的結點數為奇數,輸出中間的結點 如果鍊錶結點數為偶數,輸出中間兩個結點前面的乙個。思考 最簡單的解法 從頭到尾遍歷一遍陣列,得到鍊錶大小n。然後再從頭走n 2次,則一共需要的時間為1.5n。優化 想起以前一道題目,用n的方法反轉乙個單向鍊錶。如果只用乙個變數head...

鍊錶問題05 反轉部分單向鍊錶

題目 給定乙個單向鍊錶的頭節點head,以及兩個整數from和to,在單向鍊錶上把第from個節點到第to個節點這一部分進行反轉。例如 1 2 3 4 5 null,from 2,to 4 調整結果為 1 4 3 2 5 null 再如 1 2 3 null,from 1,to 3 調整結果為 3 ...