目录

  1. 深度优先遍历(DFS)
  2. 连通分量
  3. DFS 在连通分量中的应用
  4. 参考资料

1. 深度优先遍历(DFS)

1.1 DFS 的基本原理

深度优先搜索(DFS, Depth-First Search)是一种遍历或搜索图的算法,它采用 回溯 的思想,从起始节点开始沿着一条路径尽可能深入,直到无法继续时再回溯并尝试其他路径。

DFS 的特点

  • 时间复杂度:O(V+E)O(V + E)(邻接表),O(V2)O(V^2)(邻接矩阵)
  • 空间复杂度:O(V)O(V)(递归深度或显式栈)
  • 适用场景
    • 连通性检查(判断两个点是否连通)
    • 连通分量计算
    • 拓扑排序(DAG)
    • 二分图检测
    • 强连通分量(SCC)计算

1.2 DFS 的递归实现

无向图 DFS 递归版(Python)

class Graph:
    def __init__(self, V):
        self.V = V
        self.adj = [[] for _ in range(V)]

    def add_edge(self, u, v):
        self.adj[u].append(v)
        self.adj[v].append(u)  # 无向图

    def dfs_recursive(self, v, visited):
        visited[v] = True
        print(v, end=" ")

        for neighbor in self.adj[v]:
            if not visited[neighbor]:
                self.dfs_recursive(neighbor, visited)

g = Graph(5)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 3)
g.add_edge(3, 4)

visited = [False] * g.V
g.dfs_recursive(0, visited)

输出

0 1 3 4 2

复杂度

  • 时间复杂度:O(V+E)O(V + E)
  • 空间复杂度:O(V)O(V)(递归栈深度)

1.3 DFS 的非递归实现(显式栈)

递归 DFS 存在 栈溢出 风险,因此可以使用 显式栈 来实现非递归版本。

无向图 DFS 非递归版(Python)

def dfs_iterative(graph, start):
    visited = [False] * len(graph)
    stack = [start]

    while stack:
        v = stack.pop()
        if not visited[v]:
            visited[v] = True
            print(v, end=" ")
            stack.extend(reversed(graph[v]))  # 逆序保证遍历顺序

g = Graph(5)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 3)
g.add_edge(3, 4)

dfs_iterative(g.adj, 0)

输出

0 2 1 3 4

复杂度

  • 时间复杂度:O(V+E)O(V + E)
  • 空间复杂度:O(V)O(V)(显式栈)

2. 连通分量

2.1 无向图的连通分量

定义:无向图的连通分量(Connected Component)指的是 顶点之间互相连通,且与其他部分不连通的极大子图。

计算连通分量(Python)

def count_components(graph, V):
    visited = [False] * V
    components = 0

    def dfs(v):
        visited[v] = True
        for neighbor in graph[v]:
            if not visited[neighbor]:
                dfs(neighbor)

    for v in range(V):
        if not visited[v]:  # 发现新连通分量
            components += 1
            dfs(v)

    return components

g = Graph(6)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(3, 4)

print("连通分量个数:", count_components(g.adj, g.V))

输出

连通分量个数: 3

复杂度

  • 时间复杂度:O(V+E)O(V + E)

2.2 有向图的强连通分量(SCC)

有向图 中,强连通分量(SCC, Strongly Connected Component)是指 任意两个顶点都可以互相到达的最大子图

计算 SCC 常用 Kosaraju 算法Tarjan 算法

  • Kosaraju:两次 DFS,复杂度 O(V+E)O(V + E)
  • Tarjan:基于 Tarjan 的低链值,复杂度 O(V+E)O(V + E)

Kosaraju 算法计算 SCC(Python)

from collections import defaultdict

class Graph:
    def __init__(self, V):
        self.V = V
        self.adj = defaultdict(list)

    def add_edge(self, u, v):
        self.adj[u].append(v)

    def dfs(self, v, visited, stack):
        visited[v] = True
        for neighbor in self.adj[v]:
            if not visited[neighbor]:
                self.dfs(neighbor, visited, stack)
        stack.append(v)

    def transpose(self):
        g = Graph(self.V)
        for v in self.adj:
            for neighbor in self.adj[v]:
                g.add_edge(neighbor, v)
        return g

    def find_scc(self):
        stack = []
        visited = [False] * self.V

        for v in range(self.V):
            if not visited[v]:
                self.dfs(v, visited, stack)

        transposed = self.transpose()
        visited = [False] * self.V

        while stack:
            v = stack.pop()
            if not visited[v]:
                transposed.dfs(v, visited, [])
                print()  # 输出 SCC

g = Graph(5)
g.add_edge(0, 2)
g.add_edge(2, 1)
g.add_edge(1, 0)
g.add_edge(1, 3)
g.add_edge(3, 4)

print("强连通分量:")
g.find_scc()

复杂度

  • 时间复杂度:O(V+E)O(V + E)

4. 参考资料

出站链接

站内链接