必须填充Null才能唯一还原二叉树结构,因为无Null的层序序列无法区分左右子树缺失情况,如[1,2]可能对应左子2或右子2;带Null序列结合下标映射(左子2i+1、右子2i+2)可精确重建。

层序遍历序列中填充 Null(或占位符如 null、#、None)的目的,是保留二叉树的**结构完整性**,尤其在序列化/反序列化、LeetCode 构建测试用例、JSON 表示等场景中至关重要。仅靠原始层序序列(如 [3,9,20,15,7])无法唯一还原树形——缺少空节点信息,就无法判断某节点是否缺失左/右子,进而导致歧义。掌握“带 Null 的层序序列 → 完整二叉树结构”的还原,本质是模拟 BFS 构建过程,关键在于位置映射与空节点跳过逻辑。
为什么必须填充 Null 才能还原?
普通层序遍历(不填 Null)只输出非空节点,丢失了“空位”信息。例如两棵树:
-
Tree A:根为 1,左子为 2,右子为 null → 层序(无 Null)=[1,2] -
Tree B:根为 1,左子为 null,右子为 2 → 层序(无 Null)=[1,2]
二者层序序列完全相同,但结构相反。只有加入 Null 占位(如 [1, null, 2] vs [1, 2, null]),才能区分左右子树是否存在。因此,带 Null 的层序序列 + 明确的顺序规则(从上到下、从左到右)可唯一确定一棵二叉树。
还原的核心策略:数组下标映射法
将带 Null 的层序序列视为一个 0-indexed 数组 vals。对任意非空节点 vals[i],其:
- 左子节点位于
vals[2*i + 1] - 右子节点位于
vals[2*i + 2]
还原时按此规律逐层构建:从 i = 0 开始创建根节点,用队列缓存已创建但尚未配齐子节点的节点;每次取出队首节点 node,检查 vals[2*i+1] 和 vals[2*i+2] 是否非 Null,若是则创建对应子节点并入队;同时用计数器 i 或双指针跟踪当前处理到数组哪个位置。
实际还原步骤(以 Python 伪代码逻辑说明)
输入:列表 data = [3,9,20,null,null,15,7]
- 若
data为空或首项为null,直接返回None - 创建根节点
root = TreeNode(data[0]),初始化队列queue = [root],索引i = 0 - 当队列非空且
i 时循环:- 取出
node = queue.pop(0) -
i += 1,若data[i] != null,创建左子node.left = TreeNode(data[i])并入队 -
i += 1,若data[i] != null,创建右子node.right = TreeNode(data[i])并入队
- 取出
该过程严格遵循完全二叉树的隐式数组布局,确保每个非空节点的左右子在数组中的物理位置与其逻辑父子关系一致。
常见易错点提醒
还原失败往往不是算法错,而是对输入格式理解偏差:
-
Null 表示需统一:LeetCode 多用
None或null字符串,JSON 中可能是null,编码时注意类型判断(if val is not None而非if val) -
末尾 Null 可省略:如
[1,2,3,null,null,null,null]末尾连续 Null 通常被截断为[1,2,3],此时不能直接套用下标公式——需以实际给出的长度为准,而非假设满二叉树大小 -
不支持前序/后序混用:本策略仅适用于「层序 + Null 占位」输入;若给的是前序含 Null 序列(如
[1,2,null,null,3,4,null,null,5]),需改用 DFS 递归重建,逻辑完全不同










