迭代时修改可变可迭代对象是否合规?以BFS队列操作为例
为什么BFS中迭代时修改队列是可接受的?
问题背景
大家都知道通常不建议在迭代可变可迭代对象时修改它,但在学习BFS(广度优先搜索)实现二叉树层级遍历这类场景时,典型写法会在while循环里,基于队列的初始长度遍历当前层级元素,同时弹出队首元素并将子节点添加到队列中。这种场景下修改可变可迭代对象(队列)是否正常且可接受?
代码示例
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: res = [] q = collections.deque() # 要实现按层遍历,所以用广度优先搜索 if root: # 根节点不为空时加入队列 q.append(root) while q: # 队列非空时持续循环 val = [] # 初始化存储当前层节点值的列表 print(f'len(q) = {len(q)}\n') for i in range(len(q)): # 基于队列初始长度遍历当前层所有节点 print(f'i = {i}, len(q) = {len(q)}, q = {list(q)}\n') node = q.popleft() # BFS取出队首元素,记录其值 val.append(node.val) if node.left: # 左子节点存在则加入队列(待下一层处理) q.append(node.left) if node.right: # 右子节点存在则加入队列(待下一层处理) q.append(node.right) res.append(val) # 当前层所有节点处理完毕,将结果加入总列表 return res # 队列为空时返回最终结果
解答
这种修改是完全正常且可接受的,核心原因在于BFS的层级遍历逻辑特意利用了队列的可变特性,且循环边界是固定的:
- 内层for循环的
range(len(q))是在循环开始前就计算出当前队列的长度(也就是当前层的节点总数),range()生成的是固定的整数序列,后续队列添加子节点的操作不会改变这个循环的迭代次数 - 我们修改队列的目的是把下一层的节点加入队列,供下一轮while循环处理,这正是BFS层级遍历的核心逻辑:处理完当前层后,自然衔接下一层的待处理节点
这和“在迭代列表时删除/插入元素导致遍历异常”的情况完全不同——后者是因为迭代器依赖列表的实时长度,而这里的循环次数预先固定,队列的修改是在当前层遍历的逻辑之外,用于构建下一层的任务,不会干扰当前层的遍历流程。
简单说,这不是“在迭代时破坏迭代对象”,而是利用可变队列的特性实现层级间的衔接,属于BFS层级遍历的标准、正确写法。
内容的提问来源于stack exchange,提问作者lemfo
相关产品推荐
相关产品推荐

