Java 中计算二叉树的叶子节点

2025 年 5 月 12 日 | 阅读 4 分钟

二叉树 数据结构中,每个节点最多有两个子节点。在二叉树实践中,计算叶子节点的数量是一个主要问题。

叶子节点表示没有任何右子节点或左子节点的任何节点的最终标识。叶子节点计数任务应用于多个领域,包括层次化的 数据优化 和表达式树求值,以及决策树中的外部节点发现。

精确识别二叉树结构中的叶子节点至关重要,因为应用程序需要高效的叶子节点计数方法,尤其是对于大型树数据。

暴力破解法

对树进行基本遍历提供了一种简单的方法来计算叶子节点的数量。递归遍历方法在执行过程中检查每个节点,然后计算没有左子节点和右子节点的叶子节点。

该方法的时间复杂度为 O(N),因为它在 N 代表总节点数时访问每个节点一次。由于栈的使用,在最坏情况下(倾斜树),递归函数所需的空间复杂度为 O(H),其中 H 是树的高度。

此递归函数会检查一个节点是否为叶子节点,相应地增加计数,并对左子树和右子树递归调用自身。

使用层次遍历的迭代方法

除了 递归,我们还可以使用迭代方法,通过层次遍历 (BFS) 和队列来完成。我们逐层处理节点并计算叶子节点。时间复杂度仍然是 O(N),因为我们访问每个节点一次,空间复杂度是 O(W),其中 W 是树的最大宽度(对于完美二叉树,最坏情况是 O(N))。

此方法有助于避免由于深度递归导致的堆栈溢出问题。

使用尾递归的最优方法

尾递归优化增强了叶子节点计数,因为递归调用在整个函数调用过程中充当最后的计算步骤。由于尾递归方法,某些 JVM 和编译器会将递归操作转换为在其运行环境中作为迭代过程执行。这使得其空间效率比标准的递归解决方案有所提高。

基于尾递归的叶子节点计数算法

  1. 基本情况:如果节点为空,则返回累积计数 (count)。
  2. 叶子节点检查:如果当前节点是叶子节点(即,它没有左子节点和右子节点),则增加计数。
  3. 递归处理
    • 递归调用函数处理左子节点,并传递更新后的计数。
    • 递归调用函数处理右子节点,并传递从左子树遍历返回的更新后的计数。
  4. 最终计数
    该函数最终返回叶子节点的总数,同时确保堆栈增长最小。

输出

 
Leaf count: 3   

解释

TreeNode 类定义了一个节点结构,其中包含一个 整数 值 (val) 以及左子节点和右子节点的引用。BinaryTree 类包含尾递归函数 countLeaves,该函数以一个节点和一个累积计数作为参数。如果节点为空,则返回累积计数。如果节点是叶子节点(没有左子节点或右子节点),则增加计数。

否则,它首先递归处理左子树,更新计数,然后使用更新后的计数处理右子树。getLeafCount 函数将计数初始化为 0 并调用 countLeaves。尾递归确保每次函数调用中的最后一个操作都是递归调用,从而优化了堆栈使用,并使该方法比标准递归方法更具空间效率。

结论

计算二叉树的叶子节点是一个常见问题,有多种解决方法。暴力递归方法简单,但在深度树中可能导致堆栈溢出。迭代 BFS 方法避免了递归,但需要额外的队列空间。

尾递归方法通过减少递归堆栈使用提供了优化解决方案。每种方法都有其权衡,但在实际场景中,尾递归方法在时间和空间复杂度上都是高效的。


下一个主题Java 浅拷贝