如何正确统计二叉搜索树中各类节点数量(零子节点、单子节点、双子节点)

如何正确统计二叉搜索树中各类节点数量(零子节点、单子节点、双子节点)

Python

本文详解 BST 中 node_counts 方法的常见递归错误,指出忽略子树返回值导致计数失效的问题,并提供两种健壮实现:修正版递归累加与更简洁的闭包+列表计数方案,附可运行示例验证结果为 (4, 0, 3)。

本文详解 bst 中 `node_counts` 方法的常见递归错误,指出忽略子树返回值导致计数失效的问题,并提供两种健壮实现:修正版递归累加与更简洁的闭包+列表计数方案,附可运行示例验证结果为 (4, 0, 3)。

在实现二叉搜索树(BST)节点类型统计功能时,一个典型陷阱是:递归调用子树后未收集并累加其返回的计数值。原始代码中虽正确判断了当前节点的子节点数量(zero/one/two),却直接丢弃了左右子树递归调用的结果,导致最终仅统计了根节点自身类型,故输出恒为 (0, 0, 1) —— 这正是问题根源。

✅ 正确思路:自底向上聚合计数

每个递归调用需完成两件事:

  1. 递归处理左右子树,获取其各自统计的 (zero, one, two);
  2. 将子树结果累加到当前层变量,再根据当前节点结构更新自身类别计数。

以下是修复后的 node_counts_aux 实现:

def node_counts_aux(self, node):
    zero = 0
    one = 0
    two = 0

    if node is None:
        return zero, one, two

    # 递归获取左子树计数并累加
    z_left, o_left, t_left = self.node_counts_aux(node._left)
    zero += z_left
    one += o_left
    two += t_left

    # 递归获取右子树计数并累加
    z_right, o_right, t_right = self.node_counts_aux(node._right)
    zero += z_right
    one += o_right
    two += t_right

    # 判断当前节点类型并更新计数
    if node._left is not None and node._right is not None:
        two += 1
    elif node._left is not None or node._right is not None:  # 精简写法:只需判断“有且仅有一个非空”
        one += 1
    else:
        zero += 1

    return zero, one, two

⚠️ 注意:原代码中 elif (node._left is not None and node._right is None) or ... 可简化为 elif node._left or node._right(利用 Python 对 None 的 falsy 特性),更清晰且不易出错。

✨ 更优实践:使用闭包 + 可变容器(推荐)

避免重复传递三元组,改用内部函数操作共享列表,逻辑更直观、代码更紧凑:

NeuralText

Neural Text是一个使用机器学习自动生成文本的平台

def node_counts(self):
    """
    Returns the number of nodes with 0, 1, or 2 children in the BST.
    Use: zero, one, two = bst.node_counts()
    """
    counts = [0, 0, 0]  # [zero, one, two]

    def _traverse(node):
        if node is None:
            return
        _traverse(node._left)
        _traverse(node._right)
        # 统计当前节点
        if node._left and node._right:
            counts[2] += 1
        elif node._left or node._right:
            counts[1] += 1
        else:
            counts[0] += 1

    _traverse(self._root)
    return tuple(counts)

该方案优势明显:

  • 无返回值负担:无需设计多变量递归返回协议;
  • 状态集中管理:counts 列表在闭包内被安全修改;
  • 遍历顺序无关:前序、中序、后序均可(因统计依赖节点自身结构,而非访问时机);
  • 语义清晰:counts[0], counts[1], counts[2] 直观对应三类节点。

▶ 验证示例

对如下 BST:

    22
   /  \
  12   30
 / \   / \
8  20 25 40
  • 叶节点(0 子节点):8、20、25、40 → 共 4 个
  • 单子节点(1 子节点):无 → 共 0 个
  • 双子节点(2 子节点):22、12、30 → 共 3 个

调用 node_counts() 将准确返回 (4, 0, 3)。

? 总结

  • ❌ 错误模式:递归调用却不接收/累加返回值 → 计数失效;
  • ✅ 正确模式:子树结果必须逐层向上合并;
  • ? 最佳实践:优先采用闭包 + 可变容器(如 list)简化状态传递;
  • ? 测试建议:除完整树外,务必补充含单子节点的用例(如删去 40 后应得 (3, 1, 2)),确保边界逻辑全覆盖。
本文地址:https://www.sztg.com.cn/article/649200.html

如非特殊说明,本站内容均来自于网友自主分享,如有任何问题均请联系我们进行处理!

猜您喜欢