深度优先搜索(DFS)是一种用于遍历或搜索图(或树)的算法,其核心思想是**尽可能深地探索图的分支**,当某条路径无法继续前进时,回溯到上一个节点,选择另一条未探索的路径继续探索

图的深度优先搜索(Depth-First Search, DFS)

深度优先搜索(DFS)是一种用于遍历或搜索图(或树)的算法。其核心思想是尽可能深地探索图的分支,当某条路径无法继续前进时,回溯到上一个节点,选择另一条未探索的路径继续探索。这种“深入到底,再回溯”的特性是DFS的显著标志。

一、DFS的基本原理
  1. 起点选择:从图中任意一个起始节点开始(若图有多个连通分量,需遍历每个分量)。
  2. 探索规则
    • 访问当前节点,并标记为“已访问”(避免重复访问)。
    • 选择当前节点的一个未访问邻接节点,递归(或借助栈)深入探索该节点。
    • 若当前节点的所有邻接节点均已访问,则回溯到上一个节点,继续探索其他未访问路径。
  3. 终止条件:所有可达节点均被访问。
二、DFS的实现方式

DFS可通过递归栈(迭代) 实现,两种方式本质一致(递归的调用栈等价于手动维护的栈)。

1. 递归实现
  • 步骤

    1. 定义递归函数,参数为当前节点。
    2. 标记当前节点为已访问。
    3. 遍历当前节点的所有邻接节点,若未访问则递归调用该函数。
  • 伪代码

    visited = 集合()  # 存储已访问节点
    def dfs_recursive(node):
        if node in visited:
            return
        visited.add(node)  # 标记访问
        print(node)  # 访问节点(可替换为具体操作)
        for neighbor in 邻接表[node]:  # 遍历所有邻接节点
            dfs_recursive(neighbor)  # 递归探索
    
2. 栈(迭代)实现
  • 步骤

    1. 初始化栈,将起始节点入栈,并标记为已访问。
    2. 当栈不为空时,弹出栈顶节点并访问。
    3. 将该节点的所有未访问邻接节点入栈,并标记为已访问(注意入栈顺序可能影响遍历顺序)。
  • 伪代码

    def dfs_iterative(start):
        visited = 集合()
        stack = [start]
        visited.add(start)
        while stack:
            node = stack.pop()  # 弹出栈顶节点
            print(node)  # 访问节点
            # 逆序入栈(保证遍历顺序与递归一致,可选)
            for neighbor in reversed(邻接表[node]):
                if neighbor not in visited:
                    visited.add(neighbor)
                    stack.append(neighbor)
    
三、示例:无向图的DFS遍历

假设有如下无向图(邻接表表示):

邻接表 = {
    0: [1, 2],
    1: [0, 3, 4],
    2: [0, 5],
    3: [1],
    4: [1, 5],
    5: [2, 4]
}

以节点0为起点,DFS遍历顺序可能为:0 → 1 → 3 → 4 → 5 → 2(递归/栈实现的典型结果,具体顺序受邻接节点遍历顺序影响)。

四、DFS的应用场景
  1. 连通性分析:判断图中两点是否连通,或找出所有连通分量。
  2. 拓扑排序:在有向无环图(DAG)中,DFS可用于生成拓扑序列(逆后序遍历)。
  3. 路径搜索:如迷宫问题、求解两点间的一条路径。
  4. 解决谜题:如N皇后、数独等(通过回溯剪枝)。
  5. 检测环:在图中检测是否存在环(有向图和无向图均适用)。
  6. 生成树/森林:DFS遍历过程中,访问边构成的树称为DFS树(森林)。
五、DFS的时间与空间复杂度
  • 时间复杂度
    设图中节点数为V,边数为E。遍历所有节点和边的时间为O(V + E)(邻接表存储);若用邻接矩阵存储,时间为O(V²)(需遍历所有可能的边)。

  • 空间复杂度
    主要来自存储已访问节点的集合和递归栈(或手动栈)。最坏情况下(链状图),空间复杂度为O(V)

六、DFS与BFS的对比
特性DFS(深度优先搜索)BFS(广度优先搜索)
数据结构栈(递归调用栈或手动栈)队列
遍历方式深度优先,可能先探索远距离节点广度优先,优先探索近距离节点
适用场景连通性、拓扑排序、路径搜索(任意)最短路径(无权图)、层次遍历
空间复杂度最坏O(V)(链状图)最坏O(V)(完全图)
总结

DFS是一种直观且强大的图遍历算法,通过“深入探索+回溯”的策略,能够高效处理多种图相关问题。其递归实现简洁易懂,迭代实现则避免了递归深度限制的问题,实际应用中可根据场景选择合适的方式。

图的深度优先搜索
(Depth-First Search, DFS)

  1. 基本思想
    从图的某一顶点出发,沿一条路径尽可能深地访问,直到无法继续时回溯到上一个顶点,再选择其他未访问的邻接点继续探索。

  2. 实现方式

    • 递归实现:通过函数调用栈隐式管理回溯过程。
    • 显式栈实现:使用栈数据结构显式模拟递归过程。
  3. 算法步骤

    1. 标记起始顶点为已访问。
    2. 依次访问当前顶点的每个未访问的邻接点,递归或迭代进行深度优先搜索。
    3. 当所有邻接点均被访问后,回溯到上一层顶点。
  4. 时间复杂度

    • 邻接表存储:O(V + E)(V为顶点数,E为边数)。
    • 邻接矩阵存储:O(V²)。
  5. 应用场景

    • 拓扑排序
    • 连通分量检测
    • 迷宫求解
    • 生成树或森林
  6. 示例伪代码(递归)

    DFS(v):
        mark v as visited
        for each neighbor u of v:
            if u is not visited:
                DFS(u)
    

深度优先搜索(DFS)和广度优先搜索(BFS)是图与树遍历中最基础的两种算法,核心区别体现在遍历策略、数据结构、适用场景等方面。以下从多个维度详细对比两者的区别:

一、核心思想与遍历策略

  • 深度优先搜索(DFS)
    遵循“深入到底,回溯探索”的策略:从起始节点出发,优先沿着一条路径尽可能深入探索(访问未探索的邻接节点),直到无法继续(路径终点),再回溯到上一节点,选择另一条未探索的路径重复过程。
    形象比喻:类似走迷宫时,一条路走到黑,走不通就退回到上一个岔路口换条路走。

  • 广度优先搜索(BFS)
    遵循“逐层扩散,先近后远”的策略:从起始节点出发,优先访问其所有直接邻接节点(第一层),再依次访问这些邻接节点的邻接节点(第二层),以此类推,按层次顺序遍历所有可达节点。
    形象比喻:类似水波扩散,从起点开始,逐层向外覆盖所有节点。

二、底层数据结构

  • DFS:依赖栈(Stack)

    • 递归实现中,使用程序的“调用栈”(隐式栈);
    • 迭代实现中,需手动维护一个栈(显式栈)。
      栈的“后进先出(LIFO)”特性保证了每次优先探索最新发现的节点(即当前路径的最深节点)。
  • BFS:依赖队列(Queue)
    必须手动维护一个队列(显式队列),队列的“先进先出(FIFO)”特性保证了先访问的节点其邻接节点也优先被访问(按层次顺序)。

三、遍历顺序对比(示例)

以如下无向图为例(节点0为起点):

    0
   / \
  1   2
 / \   \
3   4   5
  • DFS遍历顺序(可能结果):
    0 → 1 → 3 → 4 → 2 → 5(先深入1的分支,回溯后再探索2的分支)。
    注:顺序受邻接节点遍历顺序影响,若先访问2再访问1,则结果可能为0→2→5→1→3→4。

  • BFS遍历顺序(唯一结果):
    0 → 1 → 2 → 3 → 4 → 5(先访问0的邻接节点1、2,再访问1的邻接节点3、4和2的邻接节点5)。

四、适用场景

  • DFS的典型应用

    • 连通性分析(如判断两点是否连通、找出所有连通分量);
    • 拓扑排序(有向无环图DAG中,通过逆后序遍历实现);
    • 路径搜索(如找出任意一条从起点到终点的路径,不保证最短);
    • 解决回溯类问题(如N皇后、数独、迷宫求解);
    • 检测图中的环(尤其是有向图)。
  • BFS的典型应用

    • 最短路径问题(在无权图中,BFS能找到起点到其他节点的最短路径);
    • 层次遍历(如树的按层打印、社交网络中“一度好友”“二度好友”统计);
    • 广度优先搜索树(用于网络爬虫按层次抓取页面);
    • 求解无权图中节点的最短距离。

五、时间与空间复杂度

指标DFSBFS
时间复杂度均为O(V + E)(邻接表存储,V为节点数,E为边数);邻接矩阵存储时为O(V²)。同DFS,与遍历所有节点和边的操作相关。
空间复杂度最坏O(V)(如链状图,栈深度等于节点数)。最坏O(V)(如完全图,队列需存储所有节点)。

六、关键区别总结

特性DFSBFS
核心策略深度优先,优先深入路径广度优先,优先扩散层次
数据结构栈(递归或手动维护)队列(手动维护)
遍历顺序非层次化,可能跳跃式访问严格层次化,按距离递增访问
路径特性不保证最短路径无权图中可找到最短路径
空间依赖依赖路径长度(栈深度)依赖当前层节点数(队列大小)
递归限制递归实现受栈深度限制(易栈溢出)迭代实现,无递归深度限制

通过以上对比可见,DFS和BFS虽同为图遍历算法,但因策略和数据结构的差异,适用场景各有侧重。实际应用中需根据问题需求(如是否需最短路径、是否涉及回溯等)选择合适的算法。

返回图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值