0Pricing
DSA Interview Prep · 课时

TreeNode 类与层序 BFS

从数组构建二叉树,使用 deque 实现 BFS 逐层打印,并用 BFS 求最大深度。

TreeNode 类与层序 BFS 是 CoddyKit 上的免费 DSA Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 DSA Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 DSA Interview Prep 课程共包含 4 节课。

TreeNode 类基础

二叉树是一种层次化数据结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。在 Python 中,我们使用一个简单的类来表示节点:class TreeNode: def __init__(self, val=0, left=None, right=None)。面试中的每个树问题都从这个定义开始——几乎在每个 LeetCode 树问题的样板代码中,您都会看到它。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

# Build a small tree manually:
#       1
#      / \
#     2   3
#    / \
#   4   5
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
print(root.val, root.left.val, root.right.val)

从数组构建树

面试题通常会给出用层序数组表示的树,其中 None 表示缺失的节点。给定索引 i 后,左子节点位于 2i+1,右子节点位于 2i+2。编写一个辅助函数,将这个数组反序列化为相互连接的 TreeNodes,是一项很有价值的实用技能,可以在练习时节省时间。

from collections import deque

def build_tree(arr):
    if not arr or arr[0] is None:
        return None
    root = TreeNode(arr[0])
    q = deque([root])
    i = 1
    while q and i < len(arr):
        node = q.popleft()
        if i < len(arr) and arr[i] is not None:
            node.left = TreeNode(arr[i])
            q.append(node.left)
        i += 1
        if i < len(arr) and arr[i] is not None:
            node.right = TreeNode(arr[i])
            q.append(node.right)
        i += 1
    return root

root = build_tree([1, 2, 3, 4, 5, None, 6])
print(root.val, root.left.val, root.right.val)

什么是 BFS,为什么使用队列

广度优先搜索(BFS)会先访问深度为 d 的所有节点,然后再访问深度为 d+1 的任何节点。这种逐层遍历正是队列(FIFO)所提供的功能:将根节点入队,然后逐个处理节点,并在处理过程中将每个节点的子节点入队。Python 的 collections.deque 为 appendleft 和 popleft 提供 O(1) 操作,因此相比普通列表,它是更合适的选择。

from collections import deque

def bfs_print(root):
    if not root:
        return
    q = deque([root])
    while q:
        node = q.popleft()
        print(node.val, end=' ')
        if node.left:
            q.append(node.left)
        if node.right:
            q.append(node.right)

root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
bfs_print(root)  # 1 2 3 4

按层 BFS:按层分组

标准 BFS 变体会在每次迭代开始时记录队列大小,以此将节点分组到不同层中。准确处理这么多个节点,收集它们的值,然后进入下一层。这样会产生一个列表的列表——这是面试中非常常见的输出格式,适用于二叉树层序遍历、之字形遍历和右侧视图等问题。

from collections import deque

def level_order(root):
    if not root:
        return []
    result = []
    q = deque([root])
    while q:
        level_size = len(q)
        level = []
        for _ in range(level_size):
            node = q.popleft()
            level.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        result.append(level)
    return result

root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
print(level_order(root))  # [[1], [2, 3], [4]]

通过 BFS 求最大深度

二叉树的最大深度等于其 BFS 遍历中的层数。只需统计完成层循环的次数即可。这会得到一个 time 复杂度为 O(n)、空间复杂度为 O(w) 的解法,其中 w 是树的最大宽度。对于平衡树,w 为 O(n/2),因此最坏情况下的空间复杂度为 O(n)。

from collections import deque

def max_depth_bfs(root):
    if not root:
        return 0
    depth = 0
    q = deque([root])
    while q:
        depth += 1
        for _ in range(len(q)):
            node = q.popleft()
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
    return depth

root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
print(max_depth_bfs(root))  # 3

二叉树的右侧视图

右侧视图返回从右侧观察树时最后可见的节点——也就是 BFS 遍历中每一层的最后一个元素。这是层序 BFS 的直接应用:在每个层循环中收集最后一个节点。time 复杂度为 O(n),队列的空间复杂度为 O(w)。

from collections import deque

def right_side_view(root):
    if not root:
        return []
    result = []
    q = deque([root])
    while q:
        level_size = len(q)
        for i in range(level_size):
            node = q.popleft()
            if i == level_size - 1:
                result.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
    return result

root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.right = TreeNode(5)
print(right_side_view(root))  # [1, 3, 5]

锯齿形层序遍历

在锯齿形遍历中,奇数层从左到右收集,偶数层从右到左收集。最简洁的实现方式是保持 BFS 队列不变,只在将各层列表追加到结果之前,简单地反转交替的层列表。使用一个布尔标志跟踪方向,并在每层结束时翻转它。这样可以避免在内层循环中处理双端队列的复杂性。

from collections import deque

def zigzag_level_order(root):
    if not root:
        return []
    result = []
    q = deque([root])
    left_to_right = True
    while q:
        level = []
        for _ in range(len(q)):
            node = q.popleft()
            level.append(node.val)
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        result.append(level if left_to_right else level[::-1])
        left_to_right = not left_to_right
    return result

root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(zigzag_level_order(root))

BFS 空间复杂度分析

BFS 使用 O(w) 的空间,其中 w 是树的最大宽度。对于包含 n 个节点的完美二叉树,最后一层有 (n+1)/2 个节点,因此 BFS 可以在队列中同时保存最多 n/2 个节点。对于宽而平衡的树,这使得 BFS 的空间消耗比 DFS (O(h))更差;但对于深度很大且退化的树,BFS 的空间消耗更好,因为此时 DFS 的调用栈深度等于 n。

# Space comparison: BFS vs DFS on a complete binary tree
# n=15 nodes, height=4
# BFS max queue size = 8 (last level)
# DFS max call stack = 4 (height)

# For a skewed tree (like a linked list):
# n=1000 nodes
# BFS max queue size = 1 (always 1 node per level)
# DFS max call stack = 1000 (recursion depth -> stack overflow!)

from collections import deque

def skewed_tree(n):
    root = TreeNode(1)
    cur = root
    for i in range(2, n+1):
        cur.right = TreeNode(i)
        cur = cur.right
    return root

root = skewed_tree(10)
print('BFS on skewed tree is safe')

二叉树的层平均值

计算每一层的平均值是 BFS 的另一个直接应用。将某一层的所有值相加,除以节点数量,然后追加到结果列表中。这个问题考查您是否能在层循环中进行算术运算。在 Python 3 中请始终使用 float 除法(即 / 运算符),并在开始时处理空树这一边界情况。

from collections import deque

def average_of_levels(root):
    if not root:
        return []
    result = []
    q = deque([root])
    while q:
        size = len(q)
        total = 0
        for _ in range(size):
            node = q.popleft()
            total += node.val
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        result.append(total / size)
    return result

root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(average_of_levels(root))  # [3.0, 14.5, 11.0]

使用 BFS 求最小深度

最小深度是从根节点到最近叶节点(没有子节点的节点)的距离。BFS 可以最优地找到它:在层序遍历中首先遇到的叶节点一定处于最小深度。遇到叶节点后立即返回当前深度。最坏情况下时间复杂度为 O(n),但对于平衡树,通常会更早结束。

from collections import deque

def min_depth(root):
    if not root:
        return 0
    q = deque([(root, 1)])
    while q:
        node, depth = q.popleft()
        # A leaf has no children
        if not node.left and not node.right:
            return depth
        if node.left:
            q.append((node.left, depth + 1))
        if node.right:
            q.append((node.right, depth + 1))
    return 0

root = TreeNode(2)
root.left = TreeNode(3)
root.left.left = TreeNode(4)
root.right = TreeNode(5)  # leaf at depth 2
print(min_depth(root))  # 2

连接同层节点

填充右侧指针问题要求将每个节点连接到同层右侧的节点。使用 BFS 可以直接完成:在每层循环中,除最后一个节点外,为所有节点设置 node.next = q[0]。这是一个经典例子:BFS 让解决方案一目了然,而 DFS 则需要仔细跟踪跨越不同子树的指针。

from collections import deque

class Node:
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next

def connect(root):
    if not root:
        return root
    q = deque([root])
    while q:
        size = len(q)
        for i in range(size):
            node = q.popleft()
            if i < size - 1:
                node.next = q[0]
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
    return root

print('BFS connect: O(n) time, O(w) space')

快速检查

测试您对本课中数据结构 & 算法——编程面试准备相关概念的理解。

课程回顾

本课介绍了:TreeNode 类的定义以及如何根据数组构建树,使用双端队列进行层序 BFS并利用层大小技巧将节点分组,以及包括最大深度、最小深度、右视图、锯齿形遍历和各层平均值在内的应用。接下来我们将探索递归 DFS 遍历顺序。

常见问题解答

「TreeNode 类与层序 BFS」课时是免费的吗?

是的 — 「TreeNode 类与层序 BFS」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 DSA Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 DSA Interview Prep 课程共包含 4 节课。

「TreeNode 类与层序 BFS」这节课中我会学到什么?

从数组构建二叉树,使用 deque 实现 BFS 逐层打印,并用 BFS 求最大深度。 你通过在浏览器中直接运行的动手代码来练习 DSA Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 DSA Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 DSA Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「TreeNode 类与层序 BFS」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 DSA Interview Prep 课中编写并运行代码吗?

能。每节 DSA Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. TreeNode 类与层序 BFS
  2. 中序、前序、后序 DFS
  3. 直径、高度与平衡树
  4. 路径和与最近公共祖先
← 返回 DSA Interview Prep