二叉树的完全性指除最后一层外其余层均填满,且最后一层节点全部靠左连续排列;不能仅凭左右子树高度差≤1判断,因这是平衡二叉树条件。

什么是二叉树的完全性,以及为什么不能只看高度差
二叉树“完全”(complete)的定义是:除了最后一层外,其他层都填满;且最后一层的节点全部靠左连续排列。关键点在于——不能只检查左右子树高度差 ≤ 1,那是平衡二叉树(AVL)的条件,和完全性无关。常见错误是把 isBalanced 和 isComplete 混为一谈,结果在 LeetCode 958 或自测用例上直接失败。
用层序遍历(BFS)检测空洞是否出现在非末尾位置
最可靠的做法是模拟层序遍历,一旦遇到 nullptr,就标记“已见空”,此后若再遇到非空节点,说明空洞出现在中间,树不完全。这个逻辑比递归判断左右子树结构更直观、不易错。
实操要点:
- 使用
std::queue<treenode></treenode>进行 BFS,从根开始入队 - 设布尔变量
seen_null = false,初始为false - 每次出队一个节点
node:- 若
node == nullptr,置seen_null = true - 若
node != nullptr但seen_null == true,立刻返回false - 否则将
node->left和node->right入队(即使为nullptr)
- 若
- 遍历结束未触发提前返回,说明满足完全性,返回
true
注意:必须把 nullptr 也入队,否则无法检测“某层中间缺失左子但有右子”的情况(例如:根有右子无左子)。
立即学习“C++免费学习笔记(深入)”;
递归方法容易漏掉哪些边界?
有人尝试用递归 + 节点编号(类似堆数组下标)来验证:对根编号为 1,左子为 2*i,右子为 2*i+1,再统计总节点数 n,最后检查最大编号是否等于 n。这方法理论上可行,但极易出错:
- 编号过程若用
int可能溢出(深度 > 30 就超INT_MAX) - 必须严格保证编号顺序与层序一致,递归顺序稍有偏差(如先右后左)就会让编号错位
- 需要额外 O(n) 空间存所有编号,或两次遍历(一次计数、一次编号),不如 BFS 一次到位
- 无法短路:哪怕第一个节点就不符合,也要跑完整棵树
所以除非题目强制要求递归,否则不建议走这条路。
LeetCode 958 的几个典型反例要手动过一遍
写完代码后,务必用这几个最小反例验证:
-
[1,2,3,null,4]→ 不完全(第 2 层左子树缺左节点,但右子树有左节点) -
[1,2,3,4,null,null,5]→ 不完全(第 3 层:4 有左无右,但 5 在更右边,中间空洞) -
[1,2,3,4,5,6]→ 完全(6 是第 3 层第 3 个,连续无空) -
[1,null,2]→ 不完全(第 1 层根有右无左,空洞在中间)
这些例子中,BFS 方法会在出队到第 2 个节点(即 nullptr)后,紧接着遇到 2(非空),立即返回 false —— 这正是你该看到的行为。
真正容易被忽略的是:BFS 中对 nullptr 的处理粒度——不是跳过,而是“占位”。少这一步,整个逻辑就垮了。


















