二叉搜索树 | 判断二叉树是否为二叉搜索树(二分查找树)Binary Search Tree

本文介绍了三种判断二叉树是否为二叉搜索树的方法,包括错误的直接比较节点与其子节点值的方法,使用中序遍历判断ArrayList降序排列的方法,以及利用Min&Max变量进行递归判断的方法。详细分析了每种方法的原理和适用情况,并通过实例演示了正确的判断流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断要求

判断一个二叉树是否为搜索树Binary Search Tree

  1. 对于每一个节点,子树的所有值小于此节点,子树的所有值大于此节点。
  2. 每一个节点的值都不重复(without duplicate values)。
class BinaryTree {

  private int key;

  private BinaryTree left, right;

  /**
   * Simple constructor.
   *
   * @param key
   *     to set as key.
   */
  public BinaryTree(int key) {
    this.key = key;
  }

  /**
   * Extended constructor.
   *
   * @param key
   *     to set as key.
   * @param left
   *     to set as left child.
   * @param right
   *     to set as right child.
   */
  public BinaryTree(int key, BinaryTree left, BinaryTree right) {
    this.key = key;
    setLeft(left);
    setRight(right);
  }

  public int getKey() {
    return key;
  }

  /**
   * @return the left child.
   */
  public BinaryTree getLeft() {
    return left;
  }

  /**
   * @return the right child.
   */
  public BinaryTree getRight() {
    return right;
  }

  public boolean hasLeft() {
    return left != null;
  }

  public boolean hasRight() {
    return right != null;
  }

  /**
   * @param left
   *     to set
   */
  public void setLeft(BinaryTree left) {
    this.left = left;
  }

  /**
   * @param right
   *     to set
   */
  public void setRight(BinaryTree right) {
    this.right = right;
  }
}

方法1:简单的比较节点与其左孩子和右孩子

对每一个节点进行操作:简单的比较节点的值与其左孩子和右孩子的值。这是初学的时候最容易想到的方法。
但是是错误的!!!我最开始的时候因为对二叉搜索树的定义理解有疏漏。写出了以下代码:

  public static boolean isTreeBST(BinaryTree tree) {
    if(tree.hasLeft()){
      if(tree.getLeft().getKey() < tree.getKey()){
        isTreeBST(tree.getLeft());  
      }else{
        return false;
      }
    }
    if(tree.hasRight()){
      if(tree.getRight().getKey() > tree.getKey()){
        isTreeBST(tree.getRight());  
      }else{
        return false;
      }
    }
    return true;
  }

回到判断要求的第一点:1. 对于每一个节点,子树的所有值小于此节点,子树的所有值大于此节点。
注意二叉搜索树的定义不是孩子的所有值小于此节点,孩子的所有值大于此节点。

在以下情况此方法的输出结果是true,其实是错误的(因为8在7的左子树,但是8大于7):

3
5
7
8
10

方法2:使用Inorder中序遍历将tree的所有节点保存在ArrayList中,判断ArrayList是否为降序排列

3
5
6
7
10

这是我发现第一种方法错误之后容易想到的另一种方法,思路比较简单,但是实现需要利用其他的数据结构。
图视这是一棵二叉搜索树。

  1. 用中序遍历(从右边开始)访问所有节点。这样可以将树中的所有节点的值由大到小的遍历。
  2. 每次访问节点,都将节点的值存入ArrayList中。
  3. 判断ArrayList是否为降序排列,同时保证无重复值。
  public static boolean isTreeBST(BinaryTree tree) {
    if(tree == null) return true;
    if((tree.hasLeft() == false) && (tree.hasRight() == false)) return true;
    List<Integer> result = new ArrayList<>();
    result = Inorder(tree, result);
    for(int i = 0; i < result.size()-1; i++){
      if(result.get(i) <= result.get(i+1)){
        return false;
      }
    }
    return true;
  }
  
  public static List<Integer> Inorder(BinaryTree tree, List<Integer> result){
    if(tree.hasRight()){
      Inorder(tree.getRight(), result);
    }
    result.add(tree.getKey());
    if(tree.hasLeft()){
      Inorder(tree.getLeft(), result);
    }
    return result;
  }

方法3:利用变量Min&max来表示整个树的bound,以此来判断每个节点,依然使用Inorder中序遍历

这个方法是学校TA提供的,以下我用Java写一遍。思路确实很精妙,思考过程比较复杂,我也在纸上画了一会儿才搞明白。但是实现过程异常的简单。

8
10
11
15
20

注意:本文讨论的树的每个节点的值都是integer

  1. 访问每一个节点的时候,都有两个变量Min&Max用来表示到目前为止这个树的上下边界。
  2. 访问节点时,比较节点的值Min&Max,在范围外则return false。
  3. 如果节点为null,则说明递归已经到了base case也就是树的边界点。一直到此的节点都在边界范围内,那么说明树没有问题,return true
  4. 如果节点不是null,那么继续开始递归到他的左右子树(更新Min&Max)。并且只有他的左右子树都能通过测试时,这个节点才能通过测试。所以用&&(and)。

这个方法最关键的是理解对于每个节点来说,什么是他的Min&Max
以上图的树为例进行分析:

  1. 从root 10 开始,因为他是root,所以可以为任何值。也就是在【Integer.MIN_VALUE, Integer.MAX_VALUE】范围内。显然10通过了范围测试
  2. 开始递归到10右子树1515的范围是多少呢?首先他需要比他的parent要大,也就是>10,也就是>=11。上边界呢?没有改变,可以非常大,只要>10就行了。所以他的范围是【10+1,Integer.MAX_VALUE】。显然15通过了范围测试
  3. 开始递归到15的右子树2020的范围是多少呢?首先他需要比他的parent要大,也就是>15,也就是>=16。上边界呢?没有改变,可以非常大,只要>16就行了。所以他的范围是【15+1,Integer.MAX_VALUE】。显然20通过了范围测试
  4. 开始递归到15的左子树1111的范围是多少呢?首先他需要比他的parent要小,也就是<15,也就是<=14。下边界呢?没有改变。所以他的范围是【11,15-1】。显然11通过了范围测试

11,20通过了测试。并且子节点都是null–> 那么以这两个点为root的树是BST,return true–>
以15为节点的树是BST,return true --> 以8为root的树是BST,return true -->
以10为节点的树是BST,return true

  public static boolean isTreeBST(BinaryTree tree) {
    return Inorder(tree, Integer.MIN_VALUE, Integer.MAX_VALUE);
  }
  
  public static boolean Inorder(BinaryTree tree, int Min, int Max){
  	if(tree.getKey() < Min || tree.getKey() > Max){
      return false;
    }
    if(tree == null) return truereturn Inorder(tree.getRight(), tree.getKey()+1, Max) && Inorder(tree.getLeft(), Min, tree.getKey()-1);
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值