給定乙個單鏈表,只給出頭指標h:
1、如何判斷是否存在環?
2、如何知道環的長度?
3、如何找出環的入口點在**?
4、帶環鍊錶的長度是多少?
解法:
1、對於問題1(判斷是否存在環),使用追趕的方法,設定兩個指標slow、fast,從頭指標開始,每次分別前進1步、2步。如存在環,則兩者相遇;如不存在環,fast遇到null退出。
2、對於問題2(求環的長度),記錄下問題1的碰撞點p,slow、fast從該點開始,再次碰撞所走過的運算元就是環的長度s,當然也可以利用slow再次走到p。
3、問題3(找出環的入口點):有定理:碰撞點p到連線點的距離=頭指標到連線點的距離,因此,分別從碰撞點、頭指標開始走,相遇的那個點就是連線點。(證明在後面附註)。
4、問題3中已經求出連線點距離頭指標的長度,加上問題2中求出的環的長度,二者之和就是帶環單鏈表的長度。
**如下
void isloop(node* head)
} if(!loop)
cout<<"this link has not loop\n";
elsewhile(p!=r);
while(p!=q)
cout<<"\nstart of loop: "問題3的證明
經過第1步確認存在環後,尋找環入口點:
演算法描述:
當fast若與slow相遇時,slow肯定沒有走遍歷完鍊錶,而fast已經在環內迴圈了n圈(1<=n)。
假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長為r,則:
2s = s + nr
s= nr
設整個鍊錶長l,環入口點
與相遇點距離為x,起點到環入口點的距離為a。則有l=a+r,l-a=r
a + x =s= nr
a + x = (n – 1)r +r = (n-1)r + l - a
a = (n-1)r + (l – a – x)
(l – a – x)為相遇點到環入口點的距離(即r - x 環的另一部分),由此可知,從煉表頭到環入口點等於(n-1)迴圈內環+相遇點到環入口點,於是我們從煉表頭、與相遇點分別設乙個指標,每次各走一步,兩個指標必定相遇,且相遇第一點為環入口點。(從碰撞點 x 前進 a 步即為連線點。)
鍊錶形狀類似數字 6 。
假設甩尾(在環外)長度為 a(結點個數),環內長度為 b 。
則總長度(也是總結點數)為 a+b 。
從頭開始,0 base 編號。
將第 i 步訪問的結點用 s(i) 表示。i = 0, 1 ...
當 i<a 時,s(i)=i ;
當 i≥a 時,s(i)=a+(i-a)%b 。
分析追趕過程:
兩個指標分別前進,假定經過 x 步後,碰撞。則有:s(x)=s(2x)
由環的週期性有:2x=tb+x 。得到 x=tb 。(x,t不是可以隨便變的變數,而是記號,分別記錄了slow走了多少步和fast比slow多走了幾圈)
另,碰撞時,必須在環內,不可能在甩尾段,有 x>=a 。
連線點為從起點走 a 步,即 s(a)。
s(a) = s(tb+a) = s(x+a)。(s(a) = s(tb+a) 和前面分析的s(x)=s(2x)無關,而是s(a) = s(nb+a),當n為任何數的時候都成立,當然為特定的t也是成立的)
得到結論:從碰撞點 x 前進 a 步即為連線點。
根據假設易知 s(a-1) 在甩尾段,s(a) 在環上,而 s(x+a) 必然在環上。所以可以發生碰撞。
綜上,從 x 點和從起點同步前進,第乙個碰撞點就是連線點。
判斷乙個單鏈表是否有環及環
判斷乙個單鏈表是否有環及環的鏈結點 蒙恩的罪人 給定乙個單鏈表,只給出頭指標h 1 如何判斷是否存在環?2 如何知道環的長度?3 如何找出環的連線點在 4 帶環鍊錶的長度是多少?解法 1 對於問題1,使用追趕的方法,設定兩個指標slow fast,從頭指標開始,每次分別前進1步 2步。如存在環,則兩...
判斷乙個單鏈表是否有環及環入口
要求 不允許修改鍊錶結構 時間複雜度o n 空間複雜度o 1 判斷是否有環 如果鍊錶有環,那麼在遍歷時則會陷入死迴圈。使用快慢指標 快指標移動2步,慢指標移動1步 如果走到某一步,快慢指標相遇,則說明有環 環入口點 我們假設鍊錶頭部到環入口距離 len,環入口到快慢指標交匯點的距離為x,環的長度為r...
判斷乙個單鏈表是否有環
一 判斷鍊錶是否存在環 設定兩個指標 fast,slow 初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入 環,而slow後進入環,兩個指標必定相遇。當然,fast先行頭到尾部為null,則為無環鏈表 程式如下 bool i itsloop listn...