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)

相关推荐
狂炫冰美式13 分钟前
电脑合盖之后 Cursor 还在偷我电?看看为啥
前端·人工智能·后端
程序员三明治14 分钟前
【体验毛坯房】Deep Harness 入门教程
java·人工智能·后端·大模型·llm·deepseek·dsh
newerp27 分钟前
Golang 切片扩容策略
后端·程序员·go
k4m7v2pz28 分钟前
用 rust-verb-shell 重写进程管理:从 game.sh 到 .rvs 的迁移实录
开发语言·后端·rust
我的div丢了肿么办31 分钟前
go中make声明切片, 修改切片,append给切片扩容,合并切片,复制切片
后端·go
Zane199444 分钟前
去重用 set 到底能快多少?实测差距接近三百倍
后端·python
未秃头的程序猿1 小时前
一次秒杀把服务打挂了,我用Sentinel规则配置化救了回来
java·后端·spring cloud
Zane19941 小时前
明明没删字段,反序列化却报错:都是隐式 serialVersionUID 惹的祸
java·后端
Gopher_HBo1 小时前
beego启动流程
后端
fliter1 小时前
Go Map 详解:键值对实际上是如何存储的
后端