使用 DFS 检测有向图中是否存在环

262 阅读2分钟

在图的深度优先搜索DFS中,边可以根据它们连接的节点及其访问状态被分类为不同类型。

图的边类型总结

在 DFS 遍历过程中,边根据连接的节点及其访问状态可以分类为以下几种类型:

  1. 树边(Tree Edge) :在 DFS 树中,从一个节点到其直接子节点的边。

  2. 回边(Back Edge) :从一个节点到其祖先节点的边,表示存在环。

  3. 前向边(Forward Edge) :从一个节点到其子树中的节点,但不直接是其子节点的边。

  4. 交叉边(Cross Edge) :从一个节点到已访问且不在其子树中的节点的边。

理解这些边类型对于分析图的结构和性质非常有用,特别是在图算法和拓扑排序等应用中。

回边(Back Edge)的定义

回边是指一条从当前节点指向其祖先节点的边(不包括直接父节点)。在 DFS 过程中,如果存在一条从节点 u 到节点 v 的边,并且 v 是 u 的祖先节点,那么这条边就是回边。

回边的检测

在 DFS 遍历图时,可以通过访问状态来检测回边:

  1. 未访问(unvisited):节点还没有被访问。
  2. 正在访问(visiting):节点已经被访问但还没有完成其所有邻接节点的探索。
  3. 已访问(visited):节点及其所有邻接节点都已经被完全探索。

当我们在访问一个节点时,如果遇到一个已经处于“正在访问”状态的邻接节点,这就意味着存在一条回边,因为这个邻接节点是当前递归路径上的祖先节点。

回边与环的关系

在有向图中,回边的存在是环存在的直接证据。因为回边连接了当前节点与其祖先节点,说明在递归路径上形成了一个循环。

代码示例

以下是一个使用 DFS 检测有向图中回边的 JavaScript 示例,这个示例可以用来检测图中是否存在环:

**function hasCycle(graph) {

    const UNVISITED = 0;

    const VISITING = 1;

    const VISITED = 2;

  


    const state = new Array(graph.length).fill(UNVISITED);

  


    function dfs(node) {

        if (state[node] === VISITING) return true// Found a back edge, hence a cycle

        if (state[node] === VISITED) return false// No cycle in this path

  


        state[node] = VISITING;

  


        for (const neighbor of graph[node]) {

            if (dfs(neighbor)) return true;

        }

  


        state[node] = VISITED;

        return false;

    }

  


    for (let i = 0; i < graph.length; i++) {

        if (state[i] === UNVISITED) {

            if (dfs(i)) return true;

        }

    }

  


    return false;

}

  


// Example usage

const graph = [

    [1],    // Node 0 has an edge to Node 1

    [2],    // Node 1 has an edge to Node 2

    [0],    // Node 2 has an edge back to Node 0, forming a cycle

    [4],    // Node 3 has an edge to Node 4

    []      // Node 4 has no edges

];

  


console.log(hasCycle(graph));  // Output: true**