
本文详解二叉树“transform to sum tree”问题的常见逻辑错误与空指针异常(nullpointerexception)成因,重点修正对空子节点的非法字段访问,并提供健壮、可读性强的递归实现方案。
本文详解二叉树“transform to sum tree”问题的常见逻辑错误与空指针异常(nullpointerexception)成因,重点修正对空子节点的非法字段访问,并提供健壮、可读性强的递归实现方案。
在“Transform to Sum Tree”问题中,目标是将每个节点的值更新为其左右子树所有节点值之和(注意:不包含自身原值,仅子树和;部分变体要求含自身,但本题标准定义为“替换为左右子树节点值总和”,最终叶节点变为 0)。原始代码的核心缺陷有两个:
-
空指针访问风险:
root.left.data和root.right.data在子节点为null时直接调用.data,触发NullPointerException; -
逻辑错误:公式
root.left.data + leftChild + root.right.data + rightChild不仅重复计算子节点值(root.left.data已被包含在leftChild的递归结果中),更违背了“仅取子树和”的语义。
✅ 正确逻辑应为:
当前节点新值 = 左子树所有节点值之和 + 右子树所有节点值之和
即:root.data = transform(root.left) + transform(root.right)
其中,transform(null) 返回 0,天然处理空子树,无需额外判空访问 .data。
以下是修复后的完整、健壮实现(静态工具方法版):
立即学习“Java免费学习笔记(深入)”;
public class BinaryTree09 {
static class Node {
int data;
Node left;
Node right;
Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
// 将树转换为 sum tree:每个节点值 = 其左右子树所有节点值之和
public static int transform(Node root) {
if (root == null) {
return 0;
}
// 递归获取左右子树的「总和」(即子树根节点转换后的值)
int leftSum = transform(root.left);
int rightSum = transform(root.right);
// 关键修正:新值仅由左右子树和构成,不访问 root.left.data 等可能为空的字段
int oldData = root.data; // 保存原值用于返回(若需)
root.data = leftSum + rightSum;
// ✅ 返回当前节点转换后的新值(即整棵子树的总和)
return root.data;
}
public static void main(String[] args) {
/* 构建示例树:
1
/ \
2 3
/ \ / \
4 5 6 7
*/
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
System.out.println("Root new value: " + transform(root));
// 输出:27 → 因为 2+3+4+5+6+7 = 27(根节点新值 = 整棵树除根外所有节点和)
// 验证结构(可选打印辅助)
// 此时树变为:
// 27
// / \
// 9 13 ← 9 = 4+5, 13 = 6+7
// / \ / \
// 0 0 0 0 ← 叶节点无子树,故为 0
}
}? 关键注意事项:
-
绝不直接访问
node.left.data或node.right.data:必须先判空(如if (node.left != null))或依赖递归返回值(transform(node.left)已安全处理 null); -
返回值语义清晰:
transform(node)应始终返回以 node 为根的整棵子树所有节点值之和(即转换完成后该子树的总和),这既是递归基础,也是父节点计算的依据; -
原值保存非必需:若仅需转换树结构,无需
oldData;但若需调试或对比,可保留; - 时间复杂度 O(n),空间复杂度 O(h)(h 为树高,递归栈深度),符合最优解要求。
通过以上修正,代码彻底规避空指针异常,并严格遵循“sum tree”定义——简洁、健壮、易于理解与维护。


















