當前位置:首頁 » 操作系統 » 檢測環演算法

檢測環演算法

發布時間: 2024-04-12 20:58:19

⑴ 無向圖中查找環的演算法有哪些

比較直觀的辦法是,從初始結點 S 開始,用深度優先的方法遍歷圖的結點,如果在這個過程中,你遇到了一個先前就已經發現過的結點(假定它叫 V),說明存在一個環。
如果你想輸出這個環,那麼就從 V 沿路返回,直到又遇到 V,途中經過的所有結點就組成了這個環。

⑵ 判斷單鏈表有沒有環的演算法中,至少需要幾個指針

演算法的思想是設定兩個指針p,
q,其中p每次向前移動一步,q每次向前移動兩步。那麼如果單鏈表存在環,則p和q相遇;否則q將首先遇到null。
這里主要理解一個問題,就是為什麼當單鏈表存在環時,p和q一定會相遇呢?
假定單鏈表的長度為n,並且該單鏈表是環狀的,那麼第i次迭代時,p指向元素i
mod
n,q指向2i
mod
n。因此當i≡2i(mod
n)時,p與q相遇。而i≡2i(mod
n)
=>
(2i
-
i)
mod
n
=
0
=>
i
mod
n
=
0
=>
當i=n時,p與q相遇。這里一個簡單的理解是,p和q同時在操場跑步,其中q的速度是p的兩倍,當他們兩個同時出發時,p跑一圈到達起點,而q此時也剛
好跑完兩圈到達起點。
那麼當p與q起點不同呢?假定第i次迭代時p指向元素i
mod
n,q指向k+2i
mod
n,其中0<k<n。那麼i≡(2i+k)(mod
n)
=>
(i+k)
mod
n
=
0
=>
當i=n-k時,p與q相遇。
解決方案:
推廣:
1.
如果兩個指針的速度不一樣,比如p,q,(
0<p<q)二者滿足什麼樣的關系,可以使得兩者肯定交與一個節點?

Sp(i)
=
pi

Sq(i)
=
k
+
qi

如果兩個要相交於一個節點,則
Sp(i)
=
Sq(i)
=>
(pi)
mod
n
=
(
k+
qi
)
mod
n
=>[
(q
-p)i
+
k
]
mod
n
=0

=>
(q-p)i
+
k
=
Nn
[N
為自然數]

=>
i
=
(Nn
-k)
/(p-q)

i取自然數,則當
p,q滿足上面等式

存在一個自然數N,可以滿足Nn
-k

p
-
q
的倍數時,保證兩者相交。

特例:如果q
是p
的步長的兩倍,都從同一個起點開始,即
q
=
2p
,
k
=0,
那麼等式變為:
Nn=i:
即可以理解為,當第i次迭代時,i是圈的整數倍時,兩者都可以交,交點就是為起點。
2.如何判斷單鏈表的環的長度?

這個比較簡單,知道q
已經進入到環里,保存該位置。然後由該位置遍歷,當再次碰到該q
位置即可,所迭代的次數就是環的長度。
3.
如何找到鏈表中第一個在環里的節點?

假設鏈表長度是L,前半部分長度為k-1,那麼第一個再環里的節點是k,環的長度是
n,
那麼當q=2p時,
什麼時候第一次相交呢?當q指針走到第k個節點時,q指針已經在環的第
k
mod
n
的位置。即p和q
相差k個元素,從不同的起點開始,則相交的位置為
n-k
從圖上可以明顯看到,當p從交點的位置(n-k)
,向前遍歷k個節點就到到達環的第一個幾點,節點k.
演算法就很簡單:
一個指針從p和q
中的第一次相交的位置起(n-k),另外一個指針從鏈表頭開始遍歷,其交點就是鏈表中第一個在環里的交點。
4.
如果判斷兩個單鏈表有交?第一個交點在哪裡?

這個問題畫出圖,就可以很容易轉化為前面的題目。

將其中一個鏈表中的尾節點與頭節點聯系起來,則很容發現問題轉化為問題3,求有環的鏈表的第一個在環里的節點。

⑶ c++判斷有向圖是否有環的演算法

通常是用鄰接矩陣來表示一個有向圖。從圖中的每一個點出發,用深度優先遍歷的演算法,如果能夠回到出發點,圖中就是有環的;如果每一個點都不能回到出發點,那麼它就是無環的。

⑷ 浣撴祴鎵嬬幆鐨勫師鐞嗘槸浠涔

浣撴祴鎵嬬幆鐨勫師鐞嗕富瑕佹槸閫氳繃鎰熷簲鍣ㄦ劅搴斾笉鍚屾柟鍚戠殑鍔犻熷害鎴栨尟鍔ㄧ瓑榪愬姩鐘跺喌銆傝繖浜涙劅搴斿櫒閫氬父浠ヤ笁杞存垨鍏杞寸殑褰㈠紡鍑虹幇錛屽彲浠ユ劅嫻嬩笉鍚屾柟鍚戠殑鍔犻熷害鎴栨尟鍔ㄣ傝繖浜涙劅搴斿櫒閫氳繃鐢靛瑰紡鍔犻熷害璁″伐浣滐紝鑳藉熻板綍鍜岃В閲婅繖浜涜繍鍔ㄧ姸鎬佺殑鏁版嵁銆
鐒跺悗錛岃繖浜涙暟鎹緇忚繃婊ゆ嘗鍜屽嘲璋鋒嫻嬬瓑榪囩▼錛岄氳繃鍚勭嶇畻娉曞拰縐戝︾紲瀵嗙殑閫昏緫榪愮畻錛屾渶緇堝皢榪欎簺鏁版嵁杞鍙樻垚鎵嬬幆APP絝鐨勫彲璇繪暟瀛椼傝繖浜涙暟鎹鍖呮嫭姝ユ暟銆佽窛紱匯佹秷鑰楃殑鍗¤礬閲屾暟鍊肩瓑錛岃兘澶熻鐢ㄦ埛鐩磋傚湴鐞嗚В鍜屼嬌鐢ㄣ
姝ゅ栵紝浣撴祴鎵嬬幆榪橀氬父閰嶅囧氱嶄紶鎰熷櫒錛屽傚績鐜囦紶鎰熷櫒銆佸姞閫熷害浼犳劅鍣ㄣ侀檧鋙轟華鍜屾皵鍘嬭$瓑錛岃兘澶熷疄鏃剁洃嫻嬬敤鎴風殑蹇冪巼銆佹ユ暟銆佸Э鍔跨瓑鏁版嵁錛屽苟灝嗚繖浜涙暟鎹杞鍖栦負鏈変環鍊肩殑淇℃伅銆傞氳繃綆楁硶浼樺寲鍜屾牎鍑嗭紝榪欎簺浼犳劅鍣ㄨ兘澶熸彁渚涘噯紜銆佸彲闈犵殑鐩戞祴緇撴灉錛屽府鍔╃敤鎴鋒洿濂藉湴浜嗚В鑷宸辯殑韜浣撶姸鍐點
浣撴祴鎵嬬幆鍐呴儴閫氬父閰嶅囦簡涓涓楂樻晥鐨勫勭悊鍣ㄥ拰涓鍧楀皬鍨嬪瓨鍌ㄨ姱鐗囷紝鑳藉熷規墜鐜鏀墮泦鍒扮殑鏁版嵁榪涜屽勭悊銆佸垎鏋愬拰瀛樺偍錛屼互渚跨敤鎴烽殢鏃舵煡鐪嬪巻鍙叉暟鎹銆佸垎鏋愰敾鐐兼晥鏋滀互鍙婂埗瀹氫釜鎬у寲鐨勯敾鐐艱″垝銆
鎬葷殑鏉ヨ達紝浣撴祴鎵嬬幆鐨勫師鐞嗘槸鍒╃敤鎰熷簲鎶鏈鍜屽悇縐嶄紶鎰熷櫒瀹炴椂鐩戞祴鍜岃板綍鐢ㄦ埛鐨勮繍鍔ㄧ姸鍐靛拰韜浣撶姸鎬侊紝鍐嶉氳繃鏁版嵁澶勭悊鍜屽垎鏋愶紝灝嗚繖浜涗俊鎮杞鍖栦負瀵圭敤鎴鋒湁鐢ㄧ殑褰㈠紡錛屽府鍔╃敤鎴鋒洿濂藉湴浜嗚В鑷宸辯殑韜浣撶姸鍐碉紝鍒跺畾涓鎬у寲鐨勯敾鐐艱″垝錛屾彁楂樺仴搴鋒按騫熾

⑸ 設計一個基於深度優先遍歷的演算法,判斷一個給定的有向圖是否包含迴路。

你好,關於DFS判斷有向圖是否存在迴路的問題,我本人編寫的考研資料中有相關的原創總結,希望對你有幫助,轉載還請註明原創出處:《大連理工大學軟體學院887專業課(2021版)》。如有問題可以加我QQ601964408交流。
法一:利用遞歸方式,在DFS對圖進行遍歷時,將遍歷過的頂點放入棧中,如果新遍歷的頂點已經存在於遞歸棧中,則說明存在一個反向邊,即存在一個環。此時棧中結點剛好是環路中的所有結點!
注意該方法沒辦法用DFS的非遞歸方法實現,因為非遞歸方法中,利用出棧的結點獲取下一個鄰接點入棧,和遞歸方式不同的地方在於,即使圖中有環,非遞歸方法中的棧也無法存儲環上的結點。(DFS的非遞歸詳見本小結後續的代碼總結部分)
代碼實現如下:
void HasCycle ( Graph G ) {
bool visited [MAX_VERTEX_NUM] ; //訪問標記數組
bool recursionStack [MAX_VERTEX_NUM] ; //標記該點是否在棧中
for ( i=0 ; i<G.vexnum ; i++) {
//mark all the vertices as not visited and not part of recursion stack
//標記所有結點均未訪問以及不在棧中
visited [i] = FALSE ;
recursionStack [i] = FALSE ;
}
//call the recursive helper function to detect cycle in different DFS trees
//調用輔助遞歸函數以檢測不同DFS樹種的環路
for ( int i =0 ; i < G.vexnum ; i++ ) //每次檢測一個連通圖
if ( CheckCyclic ( G , i , VISITED , recursionStack ) ) ;
return true ; //存在迴路
return false ; //不存在迴路
}

bool CheckCyclic ( Graph G , int v , bool [ ] visited , bool [ ] recursionStack ) {
if ( visited [v] == FALSE) {
//mark the current nodes as visited and part of recursion stack
//將當前結點的標記數組和遞歸棧標記,置為已訪問
visited [v] = TRUE ;
recursionStack [v] = TRUE ;

//recursion for all the vertices adjacent to this vertex
//遞歸該頂點附近的所有頂點
for ( Edge e = G.FirstEdge(v) ; G.IsEdge(e) ; e=G.NextEdge(e) ) {
//判斷下一結點未被訪問,進入遞歸函數判斷是否有環
if ( visited [G.ToVertex(e) ] == FALSE &&
CheckCyclic ( G , G.ToVertex(e) , visited , recursionStack) )
return TRUE ;
//當下一結點已經訪問過,並且已經在棧中,判斷有環
else if ( recusionStack (G.ToVertex(e) ) == TRUE )
return TRUE ;
}//end_for
}//end_if

//remove the vertex from recursion stack
//從遞歸棧種移除該結點
recursionStack [v] = FALSE ;
return false ; //判斷無環
}
--------------------------------------------------------------------------------------------------
法二:本方法與法一非常相似,方法一中存在三種情況,還未入棧時表示未被訪問過的點;在棧中時表示已經被訪問過但是還沒有遞歸結束;從棧中出棧時表示遞歸結束,即後代也全部被訪問過了。上述三種情況分別用 -1,0,1三種狀態來標記點。
針對上述思路,假設正在處理點v,那麼v的狀態是0,其餘正在處理的結點的狀態也是0,如果從狀態0的結點遍歷到狀態為0的結點,那麼就存在環。此時所有狀態為0的結點構成了一個環!發現存在環時遍歷輸出state數組即可,不過該方法輸出時不是按照環路的順序輸出;如果需要順序輸出環路,可增加一個cycle數組,每次記錄環路的起點位置i。用cycle[i]記錄結點i的下一個結點編號。利用遞歸的方式輸出cycle數組即可得到迴路順序。
代碼實現:
bool Found = FALSE ; //標記是否發現環路
void HasCycle ( Graph G ) {
int state [MAX_VERTEX_NUM] ; //結點狀態標識數組
for ( i=0 ; i<G.vexnum ; i++) {
state [i] = -1 ;
}
for ( int i =0 ; i < G.vexnum ; i++ ) { //每次檢測一個連通圖
CheckCyclic ( G , i , state );
if ( Found == TRUE ) ; //存在迴路
return true ;
}
return false ; //不存在迴路
}

void CheckCyclic ( Graph G , int v , int [ ] state ) {
if ( state [v] == -1) { //如果未訪問過
state [v] = 0 ; //改變該點的狀態
for ( Edge e = G.FirstEdge(v) ; G.IsEdge(e) ; e=G.NextEdge(e) ) {
if ( state [ G.ToVertex(e) ] == -1 )
CheckCyclic ( G , G.ToVertex(e) , state )
else if ( state [ G.ToVertex(e) ] == 0 ) //該圖有環
Found = TRUE ;
}//end_for
}//end_if

state [v] = 1 ; //該點遞歸結束,即後代也訪問完
}

熱點內容
冒險家選哪個配置性價比高 發布:2024-11-27 20:58:36 瀏覽:876
阿里雲伺服器可以多開嗎 發布:2024-11-27 20:58:18 瀏覽:496
圖片水印加密 發布:2024-11-27 20:52:37 瀏覽:118
php客戶管理 發布:2024-11-27 20:47:26 瀏覽:371
java數組中的對象 發布:2024-11-27 20:45:37 瀏覽:492
手機報停恢復需要的是什麼密碼 發布:2024-11-27 20:37:02 瀏覽:592
域名訪問量查詢 發布:2024-11-27 20:22:13 瀏覽:725
如何清理網頁帳號和登錄密碼 發布:2024-11-27 20:18:53 瀏覽:372
大發明解壓密碼 發布:2024-11-27 20:18:52 瀏覽:502
藍鷗c語言 發布:2024-11-27 20:14:38 瀏覽:813