C# 广度优先搜索方法 C#如何用队列实现BFS

1次阅读

因为bfs需“先进先出”,queue原生支持o(1)入队/出队且语义明确;list模拟出队为o(n),stack则变成dfs;图遍历时须用hashset判重,避免死循环

C# 广度优先搜索方法 C#如何用队列实现BFS

为什么用 Queue<t></t> 而不是其他集合

因为 BFS 的核心是“先进先出”,必须按层顺序访问节点,Queue<t></t> 是 .NET 中唯一原生支持 O(1) 入队/出队且语义明确的集合。用 List<t></t> 模拟(比如 RemoveAt(0))会导致每次出队都 O(n) 移动元素,树稍深就明显卡顿;用 Stack<t></t> 则直接变成 DFS,逻辑错位。

Queue<t></t> 实现 BFS 的关键三步

以二叉树为例,实际写法极简,但每步都有明确意图:

  • 初始化:把根节点入队 —— queue.Enqueue(root)
  • 循环处理:只要队列非空,就 Dequeue() 取出当前层第一个节点,访问它,再把它的子节点(左、右)依次 Enqueue()
  • 终止条件:队列为空,说明所有可达节点已遍历完毕

示例片段(无异常处理,聚焦主干):

var queue = new Queue<TreeNode>(); if (root != null) queue.Enqueue(root); while (queue.count > 0) {     var node = queue.Dequeue();     Console.WriteLine(node.val); // 访问     if (node.left != null) queue.Enqueue(node.left);     if (node.right != null) queue.Enqueue(node.right); }

图结构中 BFS 必须加 visited 集合

树天然无环,但图可能有环或重复边,不判重会导致死循环。常见错误是只靠队列去重 —— Queue 不提供 Contains 高效查询,且入队前未检查是否已入过队。

  • 正确做法:用 HashSet<t></t> 记录已访问节点,每次入队前先查 visited.Contains(neighbor)
  • 注意:HashSetAdd() 返回 bool,可直接用于跳过已访问节点:if (visited.Add(neighbor)) queue.Enqueue(neighbor);
  • 不要用 List<t>.Contains()</t> 替代,大数据量下性能断崖式下跌

BFS 中记录层数或距离的惯用写法

很多题目要求返回最短路径长度、最小操作步数等,不能只靠节点值,得知道当前在第几层。

  • 方法一(推荐):每轮 while 循环代表一层,用内层 for 循环固定处理当前队列长度个节点 —— int size = queue.Count; for (int i = 0; i
  • 方法二:在入队时同时存节点和对应层数,用元组或自定义类,如 Queue
  • 避免在节点类里加临时字段存 level,污染数据结构,且线程不安全

层级计数容易漏掉初始层判断,比如从起点出发算第 0 层还是第 1 层,需严格对照题意。

text=ZqhQzanResources