【问题标题】:check if a tree is a binary search tree检查一棵树是否是二叉搜索树
【发布时间】:2016-02-16 03:45:52
【问题描述】:

我编写了以下代码来检查一棵树是否是二叉搜索树。请帮我检查代码:

好的!现在编辑代码。这个简单的解决方案是有人在以下帖子中提出的:

IsValidBST(root,-infinity,infinity);

bool IsValidBST(BinaryNode node, int MIN, int MAX) 
{
     if(node == null)
         return true;
     if(node.element > MIN 
         && node.element < MAX
         && IsValidBST(node.left,MIN,node.element)
         && IsValidBST(node.right,node.element,MAX))
         return true;
     else 
         return false;
}

【问题讨论】:

  • @TimeToCodeTheRoad - 这是用什么语言编写的?如果您编辑您的问题以适当地标记您的问题,这将非常有帮助。此外,您应该使用代码标签按钮 ({}) 来格式化您的代码,以便于阅读。最后,您的代码有什么问题?我们究竟在“检查”什么,您是否遇到错误?
  • 这是 java 代码,我正在检查 BinaryNode v 是否满足二叉搜索树的属性
  • @TimeToCode,你为什么返回Pair()??
  • @TimeToCodeTheRoad - 我只是开了个玩笑:) 你可能知道 Bobby Tables 是谁 - xkcd.com/327 :)
  • 如果树中有重复的条目怎么办?不应该是 = Min.

标签: java algorithm data-structures binary-tree


【解决方案1】:

对了,另外一个简单的解决办法是按顺序访问

java code here

【讨论】:

【解决方案2】:

一个方法一次只能做一件事。此外,您做事的方式通常很奇怪。 我会给你一些几乎是Java 的伪代码。很抱歉,但我已经有一段时间没有接触 Java 了。我希望它有所帮助。看看我在问题上也做过的cmets,希望你能解决!

这样称呼你的 isBST :

public boolean isBst(BNode node)
{
    return isBinarySearchTree(node , Integer.MIN_VALUE , Integer.MIN_VALUE);
}

内部:

public boolean isBinarySearchTree(BNode node , int min , int max)
{
    if(node.data < min || node.data > max)
        return false;
    //Check this node!
    //This algorithm doesn't recurse with null Arguments.
    //When a null is found the method returns true;
    //Look and you will find out.
    /*
     * Checking for Left SubTree
     */
    boolean leftIsBst = false;
    //If the Left Node Exists
    if(node.left != null)
    {
        //and the Left Data are Smaller than the Node Data
        if(node.left.data < node.data)
        {
            //Check if the subtree is Valid as well
            leftIsBst = isBinarySearchTree(node.left , min , node.data);
        }else
        {
            //Else if the Left data are Bigger return false;
            leftIsBst = false;
        }
    }else //if the Left Node Doesn't Exist return true;
    {
        leftIsBst = true;
    }

    /*
     * Checking for Right SubTree - Similar Logic
     */
    boolean rightIsBst = false;
    //If the Right Node Exists
    if(node.right != null)
    {
        //and the Right Data are Bigger (or Equal) than the Node Data
        if(node.right.data >= node.data)
        {
            //Check if the subtree is Valid as well
            rightIsBst = isBinarySearchTree(node.right , node.data+1 , max);
        }else
        {
            //Else if the Right data are Smaller return false;
            rightIsBst = false;
        }
    }else //if the Right Node Doesn't Exist return true;
    {
        rightIsBst = true;
    }

    //if both are true then this means that subtrees are BST too
    return (leftIsBst && rightIsBst);
}

现在:如果你想找到每个子树的 MinMax 值,你应该使用一个容器(我使用了一个 ArrayList)并存储一个三元组 Node, Min, Max 代表根节点和值(显然)。

例如。

/*
 * A Class which is used when getting subTrees Values
 */
class TreeValues
{
    BNode root; //Which node those values apply for
    int Min;
    int Max;
    TreeValues(BNode _node , _min , _max)
    {
        root = _node;
        Min = _min;
        Max = _max;
    }
}

还有一个:

/*
 * Use this as your container to store Min and Max of the whole
 */
ArrayList<TreeValues> myValues = new ArrayList<TreeValues>;

现在这是一种查找给定节点的MinMax 值的方法:

/*
 * Method Used to get Values for one Subtree
 * Returns a TreeValues Object containing that (sub-)trees values
 */ 
public TreeValues GetSubTreeValues(BNode node)
{
    //Keep information on the data of the Subtree's Startnode
    //We gonna need it later
    BNode SubtreeRoot = node;

    //The Min value of a BST Tree exists in the leftmost child
    //and the Max in the RightMost child

    int MinValue = 0;

    //If there is not a Left Child
    if(node.left == null)
    {
        //The Min Value is this node's data
        MinValue = node.data;
    }else
    {
        //Get me the Leftmost Child
        while(node.left != null)
        {
            node = node.left;
        }
        MinValue = node.data;
    }
    //Reset the node to original value
    node = SubtreeRoot; //Edit - fix
    //Similarly for the Right Child.
    if(node.right == null)
    {
        MaxValue = node.data;
    }else
    {
        int MaxValue = 0;
        //Similarly
        while(node.right != null)
        {
            node = node.right;
        }
        MaxValue = node.data;
    }
    //Return the info.
    return new TreeValues(SubtreeRoot , MinValue , MaxValue);   
}

但这仅返回一个节点的值,所以我们将使用它来查找整棵树:

public void GetTreeValues(BNode node)
{
    //Add this node to the Container with Tree Data 
    myValues.add(GetSubTreeValues(node));

    //Get Left Child Values, if it exists ...
    if(node.left != null)
        GetTreeValues(node.left);
    //Similarly.
    if(node.right != null)
        GetTreeValues(node.right);
    //Nothing is returned, we put everything to the myValues container
    return; 
}

使用这个方法,你的调用应该是这样的

if(isBinarySearchTree(root))
    GetTreeValues(root);
//else ... Do Something

这几乎是Java。它应该进行一些修改和修复。找一本好的 OO 书,它会对你有所帮助。请注意,此解决方案可以分解为更多方法。

【讨论】:

  • @Muggen:我认为您检查 isBST() 的方法是错误的。在这棵树上尝试:根节点:10,然后根节点的子节点是 9 和 12。然后 9 的子节点是 8 和 40。这不是 BST,但你的代码说它是!!!如果您同意,请给我一些信任并删除 -1
  • @TimeToCode,这是根?
  • @TimeToCode 我没有给你-1。我知道问题出在哪里。让我检查一下,我会告诉你的。
  • @TimeToCode ,立即尝试,小心编辑:使用 isBst(node) !!
  • @Muggen:是的,现在看起来不错:)。我假设对于左子树,您调用 isBST(v.left, min, v.data)。感谢您的建议。从下一次开始,我一定会举出更多的例子。感谢您的时间和耐心。此外,对于右子树,我认为 isBST(v.right, v.data, max) 也可以。总的来说,你的逻辑看起来很酷而且很简单。非常感谢您的再次帮助。真的很感激。
【解决方案3】:
boolean bst = isBST(root, Integer.MIN_VALUE, Integer.MAX_VALUE);

public boolean isBST(Node root, int min, int max) {
    if(root == null) 
        return true;

    return (root.data > min &&
            root.data < max &&
            isBST(root.left, min, root.data) &&
            isBST(root.right, root.data, max));
    }

【讨论】:

    【解决方案4】:

    更新:我刚刚看到之前有人建议过这个解决方案。对不起这些家伙,也许有人仍然觉得我的版本有用

    这是一个使用 In-Order Traversal 来检查 BST 属性的解决方案。 在我提供解决方案之前,我使用了一个不允许重复的 BST 定义。这意味着 BST 中的每个值都是唯一的(这只是为了简单起见)。

    递归中序打印代码:

    void printInorder(Node root) {
        if(root == null) {                 // base case
            return;
        }
        printInorder(root.left);           // go left
        System.out.print(root.data + " "); // process (print) data
        printInorder(root.right);          // go right
    }
    

    在 BST 上进行此中序遍历之后,所有数据都应按升序排序。 例如树:

       5
     3   7
    1 2 6 9
    

    将有顺序打印:

    1 2 3 5 6 7 9
    

    现在,我们可以跟踪 In-Order 序列中的前一个值并将其与当前节点的值进行比较,而不是打印节点。如果当前节点的值小于前一个值,则表示该序列不是升序排序的,违反了BST属性。

    例如,树:

       5
     3   7
    1 8 6 9
    

    有违规行为。 3 的右子节点是 8,如果 3 是根节点就可以了。但是,在 BST 中,8 最终会成为 9 的左孩子,而不是 3 的右孩子。因此,这棵树不是 BST。 所以,遵循这个想法的代码:

    /* wrapper that keeps track of the previous value */
    class PrevWrapper {
        int data = Integer.MIN_VALUE;
    }
    
    boolean isBST(Node root, PrevWrapper prev) {
        /* base case: we reached null*/
        if (root == null) {
            return true;
        }
    
        if(!isBST(root.left, prev)) {
            return false;
        }
        /* If previous in-order node's data is larger than
         * current node's data, BST property is violated */
        if (prev.data > root.data) {
            return false;
        }
    
        /* set the previous in-order data to the current node's data*/
        prev.data = root.data;
    
        return isBST(root.right, prev);
    }
    
    boolean isBST(Node root) {
        return isBST(root, new PrevWrapper());
    }
    

    样本树的中序遍历将无法通过节点 5 的检查,因为之前的 5 中序为 8,较大,因此违反了 BST 属性。

    【讨论】:

    • 你好,检查一下之前是否有答案并在开头标记它(说真的,即使晚了几分钟:-)。
    【解决方案5】:
        boolean isBST(TreeNode root, int max, int min) {
            if (root == null) {
                return true;
            } else if (root.val >= max || root.val <= min) {
                return false;
            } else {
                return isBST(root.left, root.val, min) && isBST(root.right, max, root.val);
            }
    
        }
    

    解决此问题的另一种方法.. 与您的代码类似

    【讨论】:

      【解决方案6】:

      二叉搜索树具有以下属性,其中左节点的键必须是

      所以我们遇到的问题是,如果树中的键不是唯一的,并且完成了按顺序遍历,我们可能会得到两个按顺序遍历产生相同序列的情况,其中 1 将是有效的 bst,而另一个不会,如果我们有一棵左节点 = root(valid bst) 和右节点 = root(invalid not a bst) 的树,就会发生这种情况。

      为了解决这个问题,我们需要保持一个有效的最小/最大范围,被“访问”的键必须位于其之间,并且我们在递归到其他节点时传递这个范围。

      #include <limits>
      
      int min = numeric_limits<int>::min();
      int max = numeric_limits<int>::max();
      
      The calling function will pass the above min and max values initially to isBst(...)
      
      bool isBst(node* root, int min, int max)
      {
          //base case
          if(root == NULL)
              return true;
      
          if(root->val <= max && root->val >= min)
          {
              bool b1 = isBst(root->left, min, root->val);
              bool b2 = isBst(root->right, root->val, max);
              if(!b1 || !b2)
                  return false;
              return true;
          }
          return false;
      }
      

      【讨论】:

        【解决方案7】:

        返回 INTEGER.MIN,INTEGER.MAX 作为空树的值并没有多大意义。也许使用 Integer 并返回 null。

        【讨论】:

        • @anonymous:为什么是-1。请证明,因为这是不可接受的。我正在努力把事情做好,你只给一个-1。
        【解决方案8】:
        public void inorder()
             {
                 min=min(root);
                 //System.out.println(min);
                 inorder(root);
        
             }
        
             private int min(BSTNode r)
                 {
        
                     while (r.left != null)
                     {
                        r=r.left;
                     }
                  return r.data;
        
        
             }
        
        
             private void inorder(BSTNode r)
             {
        
                 if (r != null)
                 {
                     inorder(r.getLeft());
                     System.out.println(r.getData());
                     if(min<=r.getData())
                     {
                         System.out.println(min+"<="+r.getData());
                         min=r.getData();
                     }
                     else
                     System.out.println("nananan");
                     //System.out.print(r.getData() +" ");
                     inorder(r.getRight());
                     return;
                 }
             }
        

        【讨论】:

          【解决方案9】:

          我们在树中进行深度优先遍历,测试每个节点的有效性。如果一个给定的节点大于它在右子树中的所有祖先节点并且小于它在左子树中的所有祖先节点,则它是有效的。我们不需要跟踪每个祖先来检查这些不等式,而是检查它必须大于(其下界)的最大数和必须小于(其上界)的最小数。

           import java.util.Stack;
          
          final int MIN_INT = Integer.MIN_VALUE;
          final int MAX_INT = Integer.MAX_VALUE;
          
          public class NodeBounds {
          
          BinaryTreeNode node;
          int lowerBound;
          int upperBound;
          
          public NodeBounds(BinaryTreeNode node, int lowerBound, int upperBound) {
              this.node = node;
              this.lowerBound = lowerBound;
              this.upperBound = upperBound;
          }
          }
          
          public boolean bstChecker(BinaryTreeNode root) {
          
          // start at the root, with an arbitrarily low lower bound
          // and an arbitrarily high upper bound
          Stack<NodeBounds> stack = new Stack<NodeBounds>();
          stack.push(new NodeBounds(root, MIN_INT, MAX_INT));
          
          // depth-first traversal
          while (!stack.empty()) {
              NodeBounds nb = stack.pop();
              BinaryTreeNode node = nb.node;
              int lowerBound = nb.lowerBound;
              int upperBound = nb.upperBound;
          
              // if this node is invalid, we return false right away
              if ((node.value < lowerBound) || (node.value > upperBound)) {
                  return false;
              }
          
              if (node.left != null) {
                  // this node must be less than the current node
                  stack.push(new NodeBounds(node.left, lowerBound, node.value));
              }
              if (node.right != null) {
                  // this node must be greater than the current node
                  stack.push(new NodeBounds(node.right, node.value, upperBound));
              }
          }
          
          // if none of the nodes were invalid, return true
          // (at this point we have checked all nodes)
          return true;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-07-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-16
            • 2021-08-24
            相关资源
            最近更新 更多