用切片模拟队列需检查非空再取首元素,预分配容量避免复制panic;图遍历依id稠密性选[]bool或map;递归dfs慎用于深度不可控场景;bfs最短路径仅适用于无权图。

怎么用 queue 实现 BFS 而不 panic?
Go 没有内置队列类型,直接用切片模拟最常用,但容易在 queue = queue[1:] 时触发底层数组复制、性能掉坑,或对空切片操作 panic。关键不是“能不能用”,而是“怎么安全高效地用”。
- 始终先检查
len(queue) > 0再取queue[0],绝不能假设非空 - 用
queue = append(queue[1:], ...)替代多次queue = queue[1:],避免反复扩容 - 对树遍历,推荐预分配容量:
queue := make([]*TreeNode, 0, 128),减少内存抖动 - 图遍历中若节点 ID 稠密(如 1~1000),用整数切片
[]int比指针更省内存;稀疏 ID 或含元数据时,才用[]*Node
DFS 递归 vs 显式栈:什么时候必须换?
递归写法简洁,但 Go 默认 goroutine 栈约 2KB,深度超千层就可能 stack overflow;图中存在长链或最坏情况深度不可控时,必须改用显式栈。
- 递归适用场景:
TreeNode高度明确 ≤ 100,或已用runtime.GOMAXPROCS(1)+debug.SetMaxStack调优(不推荐) - 显式栈写法核心是把“当前节点”和“待处理子节点状态”一起压栈,例如:
stack = append(stack, struct{ node *Node; nextChild int }{node, 0}) - 无向图 DFS 若未记录访问状态,会因回边反复进出同一节点——
visitedmap 必须是全局传入,不能只靠栈帧隐含
visited 用 map 还是 slice?看 ID 是否连续
图节点标识决定空间和速度:ID 是连续小整数(如 0~999)就用 []bool,否则只能用 map[int]bool。
-
visited := make([]bool, maxID+1):O(1) 访问,内存紧凑,但 maxID 未知或过大(如 ID 是时间戳)就崩 -
visited := make(map[int]bool):动态伸缩,但哈希计算 + 内存碎片带来约 2~3 倍延迟,高频访问时明显 - DFS/BFS 中若反复新建
visited(比如多起点搜索),建议复用并用for k := range visited { delete(visited, k) }清空,而非make新 map
为什么 BFS 找最短路径必须用无权图?
BFSShortestPaths 函数返回的 dist[node] = dist[parent] + 1 成立的前提,是所有边权重为 1。一旦出现权重为 2 的边,BFS 层级数就不再等于实际距离。
- 有权图最短路径必须换 Dijkstra(优先队列)或 Bellman-Ford(支持负权)
- 常见误用:把带权图强行转成邻接表后调
BFSShortestPaths,结果dist值全错但不报错 - 调试技巧:打印出 BFS 遍历顺序和对应
dist,若发现某节点dist小于其邻居却后访问到,大概率是边权不一致
visited 没清干净、queue 空了还取首元素、或者把有权图当无权图跑 BFS —— 这些地方没日志、不 panic,但结果静默错误。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











