一次遍历同时获取叶子数和树高需DFS返回pair<int,int>,空节点{0,0},叶子节点{1,1},非叶子节点合并左右结果;C++17用结构化绑定简化,迭代法需双栈同步维护节点与状态,叶子判定必须为!left&&!right。

用一次遍历同时拿到叶子数和树高
不能分开调用两次递归(比如先 countLeaves() 再 getHeight()),否则时间复杂度变成 O(2n),且重复遍历浪费明显。核心是让单次 DFS 返回两个信息:当前子树的叶子数量 + 当前子树高度。
常见错误是试图用全局变量或引用参数“凑”两个返回值,结果在多叉路径合并时逻辑错乱(比如左右子树都非空时,误把左子树叶子数直接加右子树高度)。
- 定义结构体或 pair 作为返回类型,例如
std::pair<int int></int>(first = 叶子数,second = 高度) - 空节点返回
{0, 0};叶子节点返回{1, 1} - 非叶子节点:叶子数 = 左叶子数 + 右叶子数;高度 = max(左高度, 右高度) + 1
- 注意:高度定义为节点数(即根到最深叶的边数+1),若题目要求边数则最后减 1
C++17 结构化绑定简化写法
避免反复写 res.first/res.second,用结构化绑定让逻辑更清晰、不易出错。
示例片段:
立即学习“C++免费学习笔记(深入)”;
auto dfs(TreeNode* node) -> std::pair<int, int> {
if (!node) return {0, 0};
if (!node->left && !node->right) return {1, 1};
<pre class='brush:php;toolbar:false;'>auto [l_leaves, l_height] = dfs(node->left);
auto [r_leaves, r_height] = dfs(node->right);
return {l_leaves + r_leaves, std::max(l_height, r_height) + 1};}
没启用 C++17 的项目会编译失败,此时退回传统写法,但务必检查左右子树结果是否被正确赋值——常见坑是把 l_leaves 错写成 r_leaves 或漏加 +1 到高度。
迭代写法中如何维护双状态栈
用栈模拟递归时,每个元素必须携带「当前节点指针」+「已累计叶子数」+「当前子树高度」三元信息,但实际只需存节点指针 + 高度,叶子数可在回溯时动态累加。
更稳妥做法是用两个栈同步压入:
-
std::stack<treenode></treenode>存节点 -
std::stack<:pair int>></:pair>存对应子树的{leaves, height}
每次 pop 后,根据左右孩子是否存在决定是否 push 子节点,并将子结果合并到当前节点。难点在于判断叶子节点时机:仅当栈顶节点的左右孩子都为 nullptr 时,才把它当作叶子计入总数。
空树和单节点树的边界处理
空树(root == nullptr)应返回叶子数 0、高度 0;单节点树(root 且无子节点)应返回叶子数 1、高度 1。这两个 case 容易混淆,尤其当高度定义不明确时。
验证方法:手画三节点链状树(root→left→left),叶子数应为 1,高度应为 3(节点计数)或 2(边计数)。如果结果不符,大概率是空节点返回值设错,或叶子判定条件写成 !node->left || !node->right(这是单支树误判)。
真正叶子的判定永远是 !node->left && !node->right,少一个 && 就全乱了。


















