二叉树叶子节点深度统计需从根开始深度设为1,递归遍历时遇叶子即记录当前depth,空节点直接返回,避免将深度误作高度或忽略根为叶子的边界情况。

用递归遍历统计每个叶子的深度,别漏掉根节点为叶子的边界情况
二叉树叶子节点深度统计的核心是:在到达每个叶子时,把当前路径长度(即深度)记录下来。关键不是“算高度”,而是“走到叶子时记下走了几步”。root 为空直接返回;root 左右子树都为空时,它自己就是叶子,深度为当前层数(从 1 开始计更直观)。递归调用时传入当前深度 + 1。
常见错误是把深度定义成“子树高度”,导致根为叶子时返回 0 或 1 错乱;或者忘记在递归入口处判断空指针,触发段错误。
实操建议:
- 统一用“从根开始深度为 1”——这样
root自身为叶子时深度就是 1,语义清晰 - 递归函数参数固定为
TreeNode* node, int depth,不依赖全局变量 - 用
std::vector<int></int>收集所有叶子深度,便于后续统计频次、最大最小值等 - 示例片段:
void collectLeafDepths(TreeNode* node, int depth, vector<int>& depths) { if (!node) return; if (!node->left && !node->right) { depths.push_back(depth); return; } collectLeafDepths(node->left, depth + 1, depths); collectLeafDepths(node->right, depth + 1, depths); }</int>
非递归写法要用栈显式维护深度,别只存节点指针
用栈模拟递归时,如果只压入 TreeNode*,就丢失了路径信息。必须同步维护每个节点对应的深度——要么用两个栈(节点栈 + 深度栈),要么用结构体/对组打包。否则无法知道当前处理的是第几层。
性能上,非递归没有函数调用开销,但空间占用和递归一致(最坏 O(n));实际编码中递归更简洁,除非明确要求避免栈溢出(如极深树)。
实操建议:
- 推荐用
stack<pair int>></pair>,初始化压入{root, 1} - 每次弹出后,先检查是否为叶子,是则记录
depth;否则将非空子节点以depth + 1压栈 - 注意空
root的提前返回,避免压入空指针
统计结果常用需求:频次分布、最深/最浅叶子、深度方差
收集完所有叶子深度后,下一步通常是分析。比如题目说“统计”,可能指频次表(各深度出现几次),也可能指极值或分布特征。C++ 中用 std::map<int int></int> 记录深度 → 出现次数最自然;用 std::minmax_element 在 vector 上找最值也高效。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
容易被忽略的是:空树或单节点树的边界输出。空树应得空结果;单节点树只有一个深度为 1 的叶子。
实操建议:
- 频次统计:遍历
depths向map累加,键为深度,值为计数 - 最深叶子:用
*max_element(depths.begin(), depths.end()),前提是depths非空 - 若需深度方差,先算均值再遍历求平方差平均——注意整数除法截断,建议转
double
LeetCode 类题常考变形:只统计特定值叶子的深度,或限制最大深度
真实面试或 OJ 中很少直接问“所有叶子深度”,更多是加条件过滤。例如:“统计值为偶数的叶子节点的深度之和”,或“忽略深度大于 K 的叶子”。这时候不能先全量收集再过滤,而应在遍历时就剪枝或判断。
剪枝的关键是:一旦当前 depth > K,且节点还不是叶子,就不用继续往下递归——提前返回能省不少时间,尤其对不平衡树。
实操建议:
- 把过滤逻辑放在叶子判断分支内,比如
if (!node->left && !node->right && node->val % 2 == 0) - 加深度限制时,在递归调用前加
if (depth 判断,避免无效入栈/调用 - 函数签名可扩展为
collectLeafDepths(..., int max_depth = INT_MAX),兼顾通用性
真正写的时候,90% 场景用第一个递归方案就够了。最难的不是算法,是记住:深度从 1 开始、空指针早判、单节点树有叶子——这三点错一个,样例就过不了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










