繁体   English   中英

如何检测无向图是否具有循环并使用BFS或DFS将其输出

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM