叶子节点统计必须用递归,正确判断条件是左右子节点均为空;路径深度需回溯式递归传参;树高必须后序遍历,依据子树高度计算;三者可一次遍历合并求解。

叶子节点统计必须用递归,但要注意空节点的边界处理
统计叶子节点数量时,最直接的方式是递归遍历,但很多人在 nullptr 判断上出错:把“当前节点为空”当成叶子,或者漏判子节点全为空的情况。叶子节点定义是「左右子节点都为 nullptr」,不是“当前节点为空”。
- 递归基必须是
if (root == nullptr) return 0;,否则会崩溃或重复计数 - 判断叶子要写成
if (root->left == nullptr && root->right == nullptr),不能只看一个子节点 - 非叶子节点要继续递归左右子树并累加:
return countLeaves(root->left) + countLeaves(root->right);
路径深度(从根到某叶子)要用回溯,不能只靠全局变量
求某条路径的深度(即根到该叶子的边数),本质是找最长/最短路径长度。常见错误是只维护一个全局 maxDepth,却没在递归返回时回退当前路径长度,导致后续分支计算被污染。
- 推荐传参方式:用形参
int depth记录当前层数(根为 0 或 1 都行,但需统一),到达叶子时更新全局最大值 - 进入子节点前
depth + 1,返回前不需显式减 —— 因为栈帧自动销毁,天然回溯 - 如果用引用传参修改深度,必须在递归调用前后手动
++/--,极易出错,不建议
树的高度必须后序遍历,不能用先序或层序硬算
树的高度定义为「根节点到最远叶子的最长路径边数」,等价于「左右子树高度的最大值加 1」。这个定义决定了必须用后序遍历:先知道子树高度,才能算当前节点高度。
- 错误做法:在先序中直接
height = max(leftHeight, rightHeight) + 1—— 此时 leftHeight 和 rightHeight 还没算出来 - 正确逻辑:递归计算
leftHeight = getHeight(root->left)和rightHeight = getHeight(root->right),再取最大值加 1 - 空节点高度按惯例设为 -1(对应边数),这样单节点树高度为 0;若习惯设为 0,则单节点高度为 1 —— 关键是前后一致,别混用
三个指标可以一次遍历同时求出,但结构体返回比多趟递归更高效
叶子数、最大路径深度、树高三者都依赖整棵树的结构信息,分别调用三次递归会重复访问节点。实际项目中应合并计算,用结构体或 tuple 一次性返回多个值。
- 定义结构体如
struct Info { int leafCount; int maxHeight; int maxPathDepth; }; - 每个节点返回自己子树的这三个值,由父节点合成:叶子数相加;高度取 max + 1;路径深度取左右子树路径深度最大值再加 1(注意:路径深度是从根出发的,所以合并时不能简单取子树最大路径深度,而要取子树返回的
maxPathDepth值,因为递归已含根到叶子的累计) - 避免用 map 或动态分配存中间结果——纯栈上结构体返回,零额外内存开销
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











