C# 如何确定二叉树是否为BST

C# 如何确定二叉树是否为BST,c#,data-structures,tree,binary-tree,binary-search-tree,C#,Data Structures,Tree,Binary Tree,Binary Search Tree,我试图找出一个逻辑来确定二叉树是否是BST。我想使用索引方法,我不想使用额外的数组来存储所有传入的值,因为我们知道索引应该按顺序排序。我想检查传入值,而不必将其存储在数组中。下面是我的尝试,但不起作用 public bool CheckBST(BstNode root) { BstNode prev = new BstNode(Int32.MinValue); if (root == null)

我试图找出一个逻辑来确定二叉树是否是BST。我想使用索引方法,我不想使用额外的数组来存储所有传入的值,因为我们知道索引应该按顺序排序。我想检查传入值,而不必将其存储在数组中。下面是我的尝试,但不起作用

   public bool CheckBST(BstNode root)
        {
            BstNode prev = new BstNode(Int32.MinValue);
            if (root == null)
                return true;
            if (root.left != null)
            {
                return CheckBST(root.left);
            }
            if (prev != null && prev.data >= root.data) // means data  is not sorted hence NOT   BST
                return false;
            prev = root;
            if(root.right!=null)
            {
                return CheckBST(root.right);
            }
            return true;
        }

因此,通常在BST中,每个节点中有三件事。这就是数据和左右两个指针。如果任何节点中有两个以上的可用指针,则该节点不是BST。最好在节点级别确定该节点中的指针是否多于应有的数量。搜索树会浪费时间和资源


下面是一个很好的方法,你不需要prev

  • 递归检查max(左)是否小于或等于root

  • 递归检查min(右)是否大于root

  • 检查左侧是否为BST

  • 检查右侧是否为BST


  • 当然,在需要的地方检查空值。

    您不能每次在
    CheckBST
    中初始化
    prev
    。您可以将
    prev
    设置为全局。我还将
    prev
    设置为类型
    integer

    int prev = Int32.MinValue; //made this global and integer type
    
    public bool CheckBST(BstNode root) {
     if (root == null)
      return true;
     bool isLeftBST = CheckBST(root.left);
     if (isLeftBST == false) return false;
    
     if (prev != Int32.MinValue && prev >= root.data) // means data  is not sorted hence NOT   BST
      return false;
    
     prev = root.data; //mark the prev before traversing the right subtree
    
     return isLeftBST && CheckBST(root.right);
    
    }
    
    忽略语法问题(如果有)。我尝试了更多的伪代码


    当然,还有其他方法可以解决这个问题。类似于跟踪到目前为止的最小值和最大值(在@user1672994-answer中)。

    给定一个二叉树,下面确定它是否是有效的二叉搜索树(BST)

    • 节点的左子树仅包含键小于的节点 节点的密钥
    • 节点的右子树仅包含键更大的节点 而不是节点的键
    • 左子树和右子树也必须是二进制搜索树
    让我们看看下面的例子:

    如果您看到上面的二叉树是BST

    现在让我们看另一个例子:

    根节点的值为5,但其右子节点的值为4,这不满足上述条件。因此,给定的树不是BST

    解决方案代码:

    鉴于TreeNode的定义如下:

    public class TreeNode 
    {
        public int Val { get; set; }
        public TreeNode Left { get; set; }
        public TreeNode Right { get; set; }
        public TreeNode(int x) { this.Val = x; }
    }
    
    检查验证的代码是

    public bool IsValidBST(TreeNode root) 
    {
        return IsValidBST(root, int.MinValue, int.MaxValue);
    }
    
    private bool IsValidBST(TreeNode root, int minValue, int maxValue)
    {
        if (root == null)
        {
            return true;
        }
    
        int nodeValue = root.Val;
        if (nodeValue < minValue || nodeValue > maxValue)
        {
            return false;
        }
    
        return IsValidBST(root.Left, minValue, nodeValue - 1) && IsValidBST(root.Right, nodeValue + 1, maxValue);
    }
    

    如果您可以使
    CheckBST
    返回所检查的BST的范围(最小值、最大值),则应使用以下递归函数:

    // Defines the return value that represents BST check failure.
    const pair<int, int> kCheckFailed(Int32.MaxValue, Int32.MinValue);
    
    pair<int, int> CheckBST(const BstNode& curr)
    {
      pair<int, int> left_ret(curr.value, curr.value);
      pair<int, int> right_ret(curr.value, curr.value);
    
      // Makes sure the left subtree, if any, is a BST, and its max
      // (`left_ret.second`) is no greater than `curr.value`
      if (curr.left) {
        left_ret = CheckBST(*curr.left);
        if (left_ret == kCheckFailed || left_ret.second > curr.value)
          return kCheckFailed;
      }
    
      // Makes sure the right subtree, if any, is a BST, and its min
      // (`right_ret.first`) is not less than `curr.value`.
      if (curr.right) {
        right_ret = CheckBST(*curr.right);
        if (right_ret == kCheckFailed || right_ret.first < curr.value)
          return kCheckFailed;
      }
    
      // Returns range by combining min of left subtree and max of right subtree.
      return make_pair(left_ret.first, right_ret.second);
    }
    
    //定义表示BST检查失败的返回值。
    常量对kCheckFailed(Int32.MaxValue,Int32.MinValue);
    对检查BST(常量BST节点和当前)
    {
    对左箭头(当前值、当前值);
    对右箭头(当前值、当前值);
    //确保左子树(如果有)是BST及其最大值
    //(`left_ret.second`)不大于`curr.value`
    如果(当前左侧){
    left_-ret=CheckBST(*当前左侧);
    if(left_ret==kCheckFailed | | left_ret.second>当前值)
    返回kCheckFailed;
    }
    //确保正确的子树(如果有)是BST及其最小值
    //(`right_ret.first`)不小于`curr.value`。
    如果(当前右侧){
    右侧=检查BST(*当前右侧);
    如果(右返回==kCheckFailed | |右返回第一次<当前值)
    返回kCheckFailed;
    }
    //通过组合左子树的最小值和右子树的最大值返回范围。
    返回make_对(左后第一,右后第二);
    }
    
    请注意,
    CheckBST
    通过引用获取(子)树根,以确保节点(
    curr
    )始终有效。但是,
    curr.left
    curr.right
    可能仍然为空,在这种情况下,相应的最小值或最大值分别为
    curr.value
    ,初始化为
    ret_left
    ret_right
    • 递归,时间复杂度为O(1)

    • 删除注释行以查看如何调用它

    • 对于第一个调用过程
      isBST(root,null,null)

      public bool isBST(节点根、节点l、节点r)
      {
      //WriteLine($“处理:isBST({root?.data},{l?.data},{r?.data})”);
      if(root==null)返回true;
      如果(l!=null&&root.data=r.data)返回false;
      //Console.WriteLine($“isBST({root?.left?.data},{l},{root?.data})和&isBST({root?.right?.data},{root?.data},{r?.data})”;
      返回isBST(root.left,l,root)和&isBST(root.right,root,r);
      }
      

    问题说给定的树是二叉树,这很好地定义了BST是什么。一旦您有了一个仔细、精确的定义,那么您就可以编写代码,清楚、简单地确定是否满足需求。检查左子树是否小于(或等于?)根。直接左子树节点小于根是不够的,整个左子树必须小于根,只要您独立验证左子树也是BST,您可以通过转到左子树节点,然后转到该子节点的最终右子节点进行检查,如果该子节点小于(或等于?)根,那么这个条件就满足了。@LasseVågsætherKarlsen:不,我指的是左撇子和右撇子。“整个左子树必须是”-当然,这是第3步。但在检查左子树和右子树(如果有数百万个元素,这将花费大量时间)之前,首先应该检查直接的左子树和右子树(步骤1和2)。如果这个条件不是真的“左-左子节点本身可以是BST,但仍然有大于“根”的节点,看起来您的一步一步缺少了一两步。哦,您是对的。比较直接节点可能会提高性能,但还不够。实际上我们应该比较以下内容:“max(左)
    // Defines the return value that represents BST check failure.
    const pair<int, int> kCheckFailed(Int32.MaxValue, Int32.MinValue);
    
    pair<int, int> CheckBST(const BstNode& curr)
    {
      pair<int, int> left_ret(curr.value, curr.value);
      pair<int, int> right_ret(curr.value, curr.value);
    
      // Makes sure the left subtree, if any, is a BST, and its max
      // (`left_ret.second`) is no greater than `curr.value`
      if (curr.left) {
        left_ret = CheckBST(*curr.left);
        if (left_ret == kCheckFailed || left_ret.second > curr.value)
          return kCheckFailed;
      }
    
      // Makes sure the right subtree, if any, is a BST, and its min
      // (`right_ret.first`) is not less than `curr.value`.
      if (curr.right) {
        right_ret = CheckBST(*curr.right);
        if (right_ret == kCheckFailed || right_ret.first < curr.value)
          return kCheckFailed;
      }
    
      // Returns range by combining min of left subtree and max of right subtree.
      return make_pair(left_ret.first, right_ret.second);
    }
    
    public bool isBST(Node root, Node l, Node r)
    {
            // Console.WriteLine($"Processing: isBST({root?.data}, {l?.data}, {r?.data})");
            if (root == null) return true;
    
            if (l != null && root.data <= l.data) return false;
    
            if (r != null && root.data >= r.data) return false;
    
            // Console.WriteLine($"isBST({root?.left?.data}, {l}, {root?.data}) && isBST({root?.right?.data}, {root?.data}, {r?.data})");
            return isBST(root.left, l, root) && isBST(root.right, root, r);
    }