Go语言实战案例-广度优先遍历BFS

一、什么是广度优先遍历(BFS)?

广度优先遍历(Breadth-First Search,简称 BFS)是一种层级展开的搜索策略。

其核心思想是:先访问当前层的所有节点,再访问下一层的节点。常借助队列(Queue)实现,保证先入先出,按层推进。


二、BFS 的应用场景

应用场景 描述
树的层序遍历 从上到下、从左到右访问所有节点
图的最短路径 在无权图中找起点到终点的最短路径
二维数组搜索(如迷宫) 最少步数、感染扩散、岛屿问题
多源 BFS 同时从多个起点扩展,如火焰蔓延

三、BFS vs DFS 的区别

特性 BFS(广度优先) DFS(深度优先)
访问方式 一层一层遍历 一条路走到底
实现结构 队列(FIFO) 栈或递归(LIFO)
找最短路径 是(无权图/网格) 否(不能保证最短)
空间复杂度 O(w),w为最宽层节点数 O(h),h为最大深度

四、BFS 在树结构中的应用:层序遍历

示例:层序遍历二叉树

go 复制代码
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

Go 实现(按层收集每层元素)

go 复制代码
func levelOrder(root *TreeNode) [][]int {
    var result [][]int
    if root == nil {
        return result
    }

    queue := []*TreeNode{root}

    for len(queue) > 0 {
        size := len(queue)
        level := []int{}

        for i := 0; i < size; i++ {
            node := queue[0]
            queue = queue[1:]

            level = append(level, node.Val)

            if node.Left != nil {
                queue = append(queue, node.Left)
            }
            if node.Right != nil {
                queue = append(queue, node.Right)
            }
        }
        result = append(result, level)
    }

    return result
}

示例输入:

ini 复制代码
// 构建如下树:
//      1
//     / \
//    2   3
//   / \   \
//  4   5   6
root := &TreeNode{Val: 1}
root.Left = &TreeNode{Val: 2}
root.Right = &TreeNode{Val: 3}
root.Left.Left = &TreeNode{Val: 4}
root.Left.Right = &TreeNode{Val: 5}
root.Right.Right = &TreeNode{Val: 6}

fmt.Println(levelOrder(root))
// 输出:[[1], [2,3], [4,5,6]]

五、BFS 在图结构中的应用:最短路径

我们以无向图为例,从起点出发,寻找所有节点的最短路径长度。

图结构定义:

go 复制代码
type Graph struct {
    adj map[int][]int
}

func NewGraph() *Graph {
    return &Graph{adj: make(map[int][]int)}
}

func (g *Graph) AddEdge(u, v int) {
    g.adj[u] = append(g.adj[u], v)
    g.adj[v] = append(g.adj[v], u) // 无向图
}

BFS 实现最短路径(起点到所有点)

go 复制代码
func BFSShortestPaths(g *Graph, start int) map[int]int {
    dist := make(map[int]int)
    visited := make(map[int]bool)
    queue := []int{start}
    dist[start] = 0
    visited[start] = true

    for len(queue) > 0 {
        node := queue[0]
        queue = queue[1:]

        for _, neighbor := range g.adj[node] {
            if !visited[neighbor] {
                dist[neighbor] = dist[node] + 1
                visited[neighbor] = true
                queue = append(queue, neighbor)
            }
        }
    }

    return dist
}

示例调用:

css 复制代码
g := NewGraph()
g.AddEdge(1, 2)
g.AddEdge(1, 3)
g.AddEdge(2, 4)
g.AddEdge(3, 5)
g.AddEdge(4, 5)

dist := BFSShortestPaths(g, 1)
fmt.Println(dist) // 输出每个节点到1的最短路径长度

六、BFS 在二维数组上的应用:最短路径 or 感染扩散

经典问题:迷宫最短路径

go 复制代码
type Point struct {
    X, Y int
}

func bfsMaze(grid [][]int, start, end Point) int {
    if grid[start.X][start.Y] == 1 {
        return -1
    }

    m, n := len(grid), len(grid[0])
    visited := make([][]bool, m)
    for i := range visited {
        visited[i] = make([]bool, n)
    }

    dirs := []Point{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}

    queue := []Point{start}
    visited[start.X][start.Y] = true
    steps := 0

    for len(queue) > 0 {
        size := len(queue)
        for i := 0; i < size; i++ {
            curr := queue[0]
            queue = queue[1:]

            if curr == end {
                return steps
            }

            for _, d := range dirs {
                nx, ny := curr.X+d.X, curr.Y+d.Y
                if nx >= 0 && ny >= 0 && nx < m && ny < n && grid[nx][ny] == 0 && !visited[nx][ny] {
                    visited[nx][ny] = true
                    queue = append(queue, Point{nx, ny})
                }
            }
        }
        steps++
    }

    return -1
}

七、复杂度分析

  • 时间复杂度 :O(n)
    n 为图中节点数(或矩阵中格子数)
  • 空间复杂度 :O(n)
    用于存储访问状态、队列

八、典型题目举例(LeetCode)

题目 描述
LeetCode 102 层序遍历 二叉树的层级展开
LeetCode 200 岛屿数量 类似 BFS 求二维图中连通区域
LeetCode 542 01矩阵 多源 BFS 计算每个 1 到最近 0 的距离
LeetCode 752 打开转盘锁 最少步数解锁问题

九、常见问题与调试技巧

  • • ❗ 队列顺序不能乱,要始终保证 FIFO(先进先出)
  • • ❗ 图结构必须标记访问状态,避免重复访问
  • • ✔ BFS 是解决"最少步数"问题的首选
  • • ✔ 多源同时扩展,用多个起点一起入队即可

十、总结

项目 内容说明
算法类型 广度优先搜索
核心结构 队列(Queue)
最适用问题 最短路径、层序遍历、感染传播问题
数据结构支持 树、图、二维数组(网格)
空间复杂度 O(n)

相关推荐
lssjzmn10 分钟前
java中,synchronized 关键字与 ReentrantLock 重入锁的区别以及应用场景,注意事项
java·后端
南雨北斗18 分钟前
词性
后端
南雨北斗20 分钟前
动词的类型
后端
小厂永远得不到的男人23 分钟前
ioc 原理篇
java·后端
南雨北斗37 分钟前
英语音标
后端
ClouGence40 分钟前
三步搞定!GaussDB 实时数据入仓
数据库·后端
whitepure43 分钟前
万字详解Java枚举
java·后端
用户83562907805143 分钟前
在 Java 中读取 Excel 文件
java·后端
canonical_entropy44 分钟前
让演化可编程:XLang 与可逆计算的结构化范式
后端
郭京京44 分钟前
mongodb基础
mongodb·go