1. 问题描述:判断一棵二叉树是否是完全的BST(Binary Search Tree 二叉搜索树)
二叉查找树(Binary Search Tree),(二叉搜索树或者称为二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
其中满足二叉搜索树的一个典型的特征是使用中序遍历二叉树的时候得到的序列是一个上升序列
2. 判断二叉树有以下几种方法:
① 从根节点开始遍历二叉树,其中需要使用到递归进行遍历节点,判断根的左右节点的值与根节点的值的大小的比较,其中递归的思路是假如树有左子树那么我们遍历左子树,有右子树那么遍历右子树,左右子树都有那么我们遍历左右子树,为叶子节点的时候直接返回true即可
除了上面的判断之外还不够,还需要判断左子树中最大的节点值是否小于根节点的值,右子树中最小的节点的值是否大于根节点的值
因为有的二叉树是这样的但是它不是二叉搜索树,所以需要加上上面的判断
10
8 11
1 100 2 15
代码如下:
public class Main{
public static void main(String[] args) {
TreeNode<Integer> root = new TreeNode<Integer>(10);
TreeNode<Integer> l = new TreeNode<Integer>(8);
TreeNode<Integer> r = new TreeNode<Integer>(11);
TreeNode<Integer> ll = new TreeNode<Integer>(1);
TreeNode<Integer> lr = new TreeNode<Integer>(100);
TreeNode<Integer> rl = new TreeNode<Integer>(2);
TreeNode<Integer> rr = new TreeNode<Integer>(15);
//把树的节点连接成一棵树: 主要是通过节点之间的引用之间的关系来解决
root.left = l;
root.right = r;
l.left = ll;
l.right = lr;
r.left = rl;
r.right = rr;
boolean b1 = isBST(root);
boolean b2 = maxOf(root);
boolean b3 = minOf(root);
System.out.println(b1 && b2 && b3);
}
private static boolean isBST(TreeNode<Integer> root) {
if(root.left == null && root.right == null) return true;
else if(root.left != null) return root.val > root.left.val && isBST(root.left);
else if(root.right != null) return root.val < root.right.val && isBST(root.right);
else{
return root.val > root.left.val && root.val < root.right.val && isBST(root.left) && isBST(root.right);
}
}
private static boolean minOf(TreeNode<Integer> root) {
if(root == null) {
return true;
}
TreeNode<Integer> p = root;
p = p.right;
if(p == null) return true;
if(p != null){
while(p.left != null){
p = p.left;
}
}
System.out.println("最小值: " + p.val);
return p.val > root.val;
}
private static boolean maxOf(TreeNode<Integer> root) {
if(root == null) return true;
TreeNode<Integer> p = root;
p = p.left;
if(p == null) return true;
if(p != null){
while(p.right != null){
p = p.right;
}
}
System.out.println("最大值: " + p.val);
return p.val < root.val;
}
}
② 使用典型判断是否是二叉搜索树的办法是使用中序遍历,把中序遍历的结果放入到一个数组中,遍历数组两两比较数组中的元素是否是有序的,假如发现有的不满足条件说明不是完全的BST
代码如下:
import java.util.ArrayList;
public class Main {
// 中序遍历是否有序
public boolean checkBST(TreeNode root) {
if (root == null)
return false;
ArrayList<Integer> list = new ArrayList<>();
inorder(root, list);
return checkOrdered(list);
}
// 递归方式把节点按中序遍历顺序加入到列表中
private void inorder(TreeNode<Integer> node, ArrayList<Integer> list) {
if (node == null)
return;
if (node.left != null) {
inorder(node.left, list);
}
list.add(node.val);
if (node.right != null) {
inorder(node.right, list);
}
}
//遍历列表,前后两两比较,如果逆序,返回false
private boolean checkOrdered(ArrayList<Integer> list) {
for (int i = 0; i < list.size() - 2; i++) {
if (list.get(i) > list.get(i + 1))
return false;
}
return true;
}
}
③ 在中序遍历的基础上我们可以使用全局变量来记录遍历到的根节点的最大值与左子树的值进行比较,其中递归的时候需要更新根节点的最大值,对于右子树的判断也是一样的,因为左右子树是对称的
代码如下:
import org.junit.Test;
/*
public class TreeNode {
int data = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int data) {
this.data = data;
}
}*/
public class Main {
public boolean checkBST(TreeNode<Integer> root) {
if (root == null)
return true;
//检查左子树,如果左子非bst立即返回false
boolean leftIsBST = checkBST(root.left);
if (!leftIsBST)
return false;
//根的值小于等于左子树的最大值,返回false
if (root.val <= preValue) {
return false;
}
//更新最后访问的值,检查右子树
preValue = root.val;
return checkBST(root.right);
}
private int preValue = Integer.MIN_VALUE;
@Test
public void test1() {
TreeNode<Integer> root = new TreeNode(9);
root.left = new TreeNode(2);
root.right = new TreeNode(20);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(15);
root.right.right = new TreeNode(28);
// root.right.left.left = new TreeNode(8);
root.right.left.left = new TreeNode(10);
root.right.left.right = new TreeNode(16);
root.right.right.left = new TreeNode(25);
root.right.right.right = new TreeNode(29);
}
@Test
public void test2() {
TreeNode root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(5);
root.right.left = new TreeNode(3);
}
}