【问题标题】:How to prove a binary tree is indeed a binary search tree? [duplicate]如何证明二叉树确实是二叉搜索树? [复制]
【发布时间】:2011-03-24 05:47:41
【问题描述】:

给定一棵简单的二叉树,我们如何证明这棵树是二叉搜索树?当我们遍历二叉树时,我们如何知道我们所在的节点是其父节点的左子节点还是右子节点?我想出了一个解决方案,我会在递归函数调用中传递一些标志,它可以跟踪节点是其父节点的左子还是右子,并且我们需要一个父节点指针,我们可以通过它进行比较:-

if(flag == 'L' && node->value < node->parent->value)
   then continue recursion;
else{
   print "not a binary search tree"
   exit;
}

同样,R 需要一个 if 条件。除此之外,你还能想到其他有效的方法吗?

提前致谢:)

【问题讨论】:

    标签: algorithm


    【解决方案1】:

    我只是检查一下:

    currentNode.Left.max() &lt; currentNode.ValuecurrentNode.Left.isBinarySearchTree()。如果两者都满足,则为二叉搜索树。

    编辑:

    上面确实遍历了左树两次(一次用于max(),一次用于isBinarySearchTree。但是,只需一次遍历即可完成:

    在你的树类中存储最小和最大元素。更新等当然可以在 O(1) 空间和时间内完成。

    然后,不使用max(),而是创建一个方法isInRange(m,M),检查(子)树是否只包含(m,m+1,...,M)范围内的元素。

    定义isInRange(m,M)如下:

    bool isInRange(m,M){
     if (m < currentNode.Value <= M){
      return (currentNode.Left.isInRange(m, currentNode.Value) && currentNode.Right.isInrange(currentNode.Value+1, M));
     }
     return false;
    }
    

    那么,初始调用将是root.isInRange(globalmin, globalmax)

    没有测试它,所以我不知道它是否对性能很重要。

    【讨论】:

    • 当然,右子树的标准相同。
    • 非常好:)。不知道为什么它没有在我的脑海中点击。
    • +1:优秀的递归答案。这使得验证子节点是否为左节点的检查变得不必要(我们将通过检查 node == node-&gt;parent-&gt;left 来完成)。
    【解决方案2】:

    简单的答案是按顺序深度优先树遍历并检查节点是否有序。

    示例代码(Common Lisp):

    (defun binary-search-tree-p (node)
      (let ((last-value nil))
        (labels ((check (value)
                   (if (or (null last-value)        ; first checked value
                           (>= value last-value))
                       (setf last-value value)
                       nil))
                 (traverse (node)
                   (if (null node)
                       t
                       (and (traverse (left node))        ; \
                            (check (value node))          ;  > in-order traversal
                            (traverse (right node))))))   ; /
          (traverse node))))
    

    【讨论】:

      【解决方案3】:

      您是否已经有办法迭代/遍历树的元素?然后你可以简单地遍历树并检查每个元素是否大于前一个

      【讨论】:

      • 必须是深度优先迭代。
      • @Henk,当然可以。我假设如果树有设施,它会是深度优先。
      【解决方案4】:

      您可以在树上进行深度优先搜索,而无需一次缓存每个子树的最小值和最大值,但您必须小心,因为比较父级及其子级之间的值不是足够的。例如,在树中:

      (10
         (7
           nil
           (20 nil nil)
         )
         nil
      )
      

      根 (10) 的左孩子 (7) 满足不等式 (7 = 7) 的右孩子 (20) 也是如此。但是,这棵树不是 BST(Binary Search Tree),因为 20 不应该在 10 的左子树中。

      要解决此问题,您可以遍历传递给指定子树有效间隔的额外参数。

      // The valid interval for the subtree root's value is (lower_bound, upper_bound).
      bool IsBST(const node_t* tree, int lower_bound, int upper_bound) {
        if (tree == NULL) return true;  // An empty subtree is OK.
        if (tree->value <= lower_bound) return false;  // Value in the root is too low.
        if (tree->value >= upper_bound) return false;  // Value in the root is too high.
      
        // Values at the left subtree should be strictly lower than tree->value
        // and be inside the root valid interval.
        if (!IsBST(tree->left, lower_bound, tree->value))
          return false;
      
        // Values at the left subtree should be strictly greater than tree->value
        // and be inside the root valid interval.
        if (!IsBST(tree->right, tree->value, upper_bound))
          return false;
      
        // Everything is OK, it is a valid BST.
        return true;  
      }
      

      请注意,通过保持原始有效区间,该函数将检测到 20 在该位置无效,因为它不在 (7, 10) 内。第一次调用应该以无限间隔完成,例如:

      IsBST(tree, INT_MIN, INT_MAX);
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 2012-06-05
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多