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 ...