[英]How to detect if an undirected graph has a cycle and output it using BFS or DFS
關於此的另一個問題僅回答了如何檢測周期,也沒有輸出周期。 因此,我想在無向圖上編寫一個在O(V + E)時間(V =頂點,E =邊)中運行BFS或DFS的算法,並輸出一個循環。
到目前為止,我所了解的是BFS / DFS的工作方式,並且如果您訪問已被標記為已訪問的節點,則可以使用BFS來檢測周期。
要使用DFS檢測和輸出循環,只需在到達每個頂點時對其進行標記即可; 如果標記了當前頂點的任何子代,則說明您有一個涉及該子代的循環。 此外,您知道該子頂點是DFS遇到的屬於該特定循環的第一個頂點,並且自DFS首次遇到該頂點以來DFS中的每個移動(即此后尚未返回的每個遞歸調用)在循環中訪問了另一個頂點。 您需要傳遞回調用堆棧的唯一信息是此子頂點,或者是一個特殊值,指示未找到循環。 您可以將此作為返回值傳回:
dfs(v, p) {
marked[v] = true
For each neighbour u of v:
If u != p: # I.e. we ignore the edge from our parent p
If marked[u]:
Append v to cycleVertices
Return u # Cycle!
Else:
result = dfs(u, v)
If result == FINISHED:
# Some descendant found a cycle; now we're just exiting
Return FINISHED
Else if result != NOCYCLE:
# We are in a cycle whose "top" vertex is result.
Append v to cycleVertices
If result == v:
return FINISHED # This was the "top" cycle vertex
Else:
return result # Pass back up
marked[v] = false # Not necessary, but (oddly?) not harmful either ;)
Return NOCYCLE
}
在為某個頂點r
(以及任何非頂點值nil
)調用dfs(r, nil)
,如果找到一個cycleVertices
則會為其填充一個循環。
[編輯:正如胡安·洛佩斯(Juan Lopes)所指出的那樣,未標記頂點是不必要的,並且可能會造成混淆; 但是,有趣的是,它不會影響無向圖的時間復雜度。]
如果您使用的是DFS,則可以根據所訪問的節點是否已經被訪問來打印出節點的名稱,以遞歸方式進行操作:
define function DFSVisit(node, cycle):
if node.visited is true:
push node.name to cycle
return true
else
set node.visited to true
for each child of node:
if DFSVisit(child, cycle) is true:
set foundCycle to true
break out of for loop
if foundCycle is true:
if (cycle.length <= 1 or cycle[first] != cycle[last]):
push node.name to cycle
return true
else
return false
到最后,循環將包含在圖中找到的循環,否則它將為空。 還要注意,顯示循環的順序取決於您對循環的“推”方式(向后推將向后打印,向前推將按順序打印)
編輯:非常感謝@j_random_hacker幫助我調試了偽代碼!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.