前言
本文将介绍什么是搜索二叉树以及如何判断一棵二叉树是否是搜索二叉树。
正文
搜索二叉树
搜索二叉树又称为二叉搜索树、二叉排序树,他首先是一个二叉树,这个二叉树可以是一个空树也可以非空,一棵搜索二叉树具有以下特性:
- 若他的左子树不为空,则左子树上所有节点的值都小于根节点的值。
- 若他的右子树不为空,则右子树上所有节点的值都大于根节点的值。
- 他的左右子树也分别为二叉搜索树。
一棵二叉树的任意节点都满足上面三个特性的话,那么这棵二叉树就是搜索二叉树。
例如,下面图中就是一个搜索二叉树。
思路分析
如何判断一个二叉树是否是搜索二叉树呢?
方式一
根据搜索二叉树的特性,我们可以观察到,他的中序遍历方式是严格递增的,所以可以采用中序遍历的方式,如果中序遍历得到的结果都是严格递增的,那么这个二叉树肯定是搜索二叉树。
方式二
第二种方法就是采用递归来实现。
采用递归的话,递归条件怎么判断呢?
- 如果一个节点的左子树是搜索二叉树,并且左子树的最大节点比这个节点小
- 这个节点的右子树也是搜索二叉树,并且右子树的最小节点比这个节点大
- 满足上面两个条件的话,那么这个二叉树就是搜索二叉树。
因为递归时,会判断每一个节点,但是在递归比较时,我们需要以下几个信息:
- 左子树的最大值
- 右子树的最小值
- 是否是搜索二叉树
为了每次递归返回的信息是一致的,也为了简化代码的调用,所以我们定义一个类,包含3个字段:是否是搜索二叉树(isBST)、最大值(max)、最小值(min)。
如果一个节点,他没有左子树和右子树,那么这个节点是搜索二叉树吗?是的,也符合搜索二叉树的条件。
代码实现
首先定义一个二叉树的节点,代码如下:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
采用递归的方式,递归时返回3个信息,定义一个结果类,代码如下:
public class Result {
public boolean isBST;
public int max;
public int min;
public Result(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
递归函数,递归处理判断每一个节点,代码如下:
public Result func(TreeNode node) {
if (node == null) {
return null;
}
// 收集左节点的信息,看左节点是否是搜索二叉树
Result leftResult = func(node.left);
// 收集右节点的信息,看右节点是否是搜索二叉树
Result rightResult = func(node.right);
int max = node.val;
int min = node.val;
if (leftResult != null) {
max = Math.max(leftResult.max, max);
min = Math.min(leftResult.min, min);
}
if (rightResult != null) {
max = Math.max(rightResult.max, max);
min = Math.min(rightResult.min, min);
}
// 先默认是搜索二叉树
boolean isBST = true;
// 如果左节点不是搜索二叉树, 那么整体也不是搜索二叉树
if (leftResult != null && !leftResult.isBST) {
isBST = false;
}
// 如果右节点不是搜索二叉树, 那么整体也不是搜索二叉树
if (rightResult != null && !rightResult.isBST) {
isBST = false;
}
// 左子树的最大值是否小于节点值
boolean leftMaxLessX = leftResult == null || (leftResult.max < node.val);
// 右子树的最小值是否大于节点值
boolean rightMinMoreX = rightResult == null || (rightResult.min > node.val);
// 有一个不符合也不是搜索二叉树
if (!(leftMaxLessX && rightMinMoreX)) {
isBST = false;
}
return new Result(isBST, max, min);
}
总结
本文将介绍什么是搜索二叉树以及如何判断一棵二叉树是否是搜索二叉树,在本次代码实现部分采用了递归方式,当然本次代码写的有点啰嗦,还有可优化的地方,若采用中序遍历的方式的话也是比较简单,这里就不再实现了。