一、概念
二叉搜索树也叫二叉排序树。在一颗二叉搜索树中,他的左子树二点节点值一定比根节点的值小,他的右子树节点的值一定比根节点的值大。
二、特点
- 他的左子树节点的值一定比根节点的值小 
- 他的右子树节点的值一定比根节点的值大 
- 他的每一颗子树都是一颗二叉搜索树 
- 他的查找效率很高,类似二分查找O(logn) 
三、代码实现
- 准备字段
 
需要准备的有二叉树的节点类跟根节点
public class BinaryTree {
    static class TreeNode {
        public int val;      //节点的值
        public TreeNode left;//左孩子地址
        public TreeNode right;//右孩子地址
        public TreeNode(int val) {
            this.val = val;
        }
    }
    public TreeNode root;   //根节点
}2.查找
二叉搜索树里的查找很简单,我们拿要查找的值鱼根节点进行比较,如果比根节点大就去根节点的右子树查找,如果比根节点小就去根节点的左边查找,如果相等就返回根节点。
public class BinaryTree {
    static class TreeNode {
        public int val;      //节点的值
        public TreeNode left;//左孩子地址
        public TreeNode right;//右孩子地址
        public TreeNode(int val) {
            this.val = val;
        }
    }
    public TreeNode root;   //根节点
    /**
     * 查找返回找到的节点
     * @param key
     * @return
     */
    public TreeNode search(int key){
        //定义一个节点代替根节点去遍历查找
        TreeNode cur = root;
        
        //循环查找
        while (cur != null) {
            if (cur.val < key) {
                //如果key的值比根节点的值大就去右子树查找
                cur = cur.right;
            } else if (cur.val > key) {
                //如果key的值比根节点的值大就去左子树查找
                cur = cur.left;
            } else {
                //说明找到了,就返回节点
                return cur;
            }
        }
        
        //没找到返回空
        return null;
    }
}- 插入
 
我们先构造一颗二叉搜索树,然后在这棵树里分别插入元素8,9,0
 
    
   插入8:比3大在右子树找合适的位置,比4的往右,比5大往右插入到5的右边
9跟0类似,我们发现每次插入的元素都会到叶子节点,于是我们只需要找到合适的叶子节点,然后再判断插入叶子节点的左边还是右边
public void insert(int val){
        //创建节点
        TreeNode node = new TreeNode(val);
        
        //创建节点代替跟节点遍历找到合适位置,并记录父亲节点的位置
        TreeNode parent = null;
        TreeNode cur = root;
        
        //遍历
        while (cur != null){
            if(cur.val < val){
                //去右子树
                parent = cur;
                cur = cur.right;
            }else  if(cur.val > val){
                //去左子树
                parent = cur;
                cur = cur.left;
            }else {
                //说明已经存在值了,直接返回
                return;
            }
        }
        
        //此时cur = null parent指向的位置就是要插入的叶子节点
        if(parent.val < val) {
            //说明比该叶子节点值大,插入右边
            parent.right = node;
        }else {
            //插入左边
            parent.left = node;
        }
    }- 删除
 
删除操作就需要进行分类:如果要删除的节点没有左孩子;如果要删除的节点没有右孩子;如果要删除的节点有左右孩子
- 待删节点没有左孩子
 
当我们找到这个节点后发现他没有左孩子,此时我们有需要进行讨论:这个节点是不是根节点;这个节点是他父亲节点的左孩子;这个节点是他父亲节点的右孩子。
- 跟节点
 
他是跟节点时,由于没有左孩子,所以直接让跟节点的右孩子指向跟节点的右孩子
 
   - 是父亲的左孩子
 
他是父亲节点的左孩子且他没有左孩子,所以此时直接让父亲节点的左孩子指向这个节点的右孩子
 
   - 是父亲的右孩子
 
他是父亲节点的右孩子且他没有左孩子,所以此时直接让父亲节点的右孩子指向这个节点的右孩子
 
   - 待删节点没有右孩子
 
当我们找到这个节点后发现他没有右孩子,此时我们有需要进行讨论:这个节点是不是根节点;这个节点是他父亲节点的左孩子;这个节点是他父亲节点的右孩子。
- 跟节点
 
是根节点且没有右孩子,说明只有左孩子,删除根节点只需要将根节点指向根节点的左孩子
 
   - 是父亲的左孩子
 
由于待删节点没有右孩子,所以直接让他的父亲的左边指向待删节点的左孩子
 
   - 是父亲的右孩子
 
由于待删节点没有右孩子,所以直接让父亲的右边指向待删节点的左孩子
 
   - 待删节点有左右孩子
 
当既有左孩子又有右孩子时,我们此时使用替换删除,也就是在待删节点的左子树去找最大值(左子树的最右边)或者右子树的最小值(右子树的最左边)找到后,与待删节点的值进行交换后删除找到的该节点
 
   public void remove(int key){
        //先找到该节点与其父亲节点
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null){
            if(cur.val < key){
                parent = cur;
                cur = cur.right;
            }else if(cur.val > key){
                parent = cur;
                cur = cur.left;
            }else {
                //找到进行删除
                delete(parent,cur);
                return;
            }
        }
    }
    private void delete(TreeNode parent, TreeNode cur) {
        if(cur.left == null){
            //没有左子树
            if(cur == root){
                //如果是跟节点
                root = root.right;
            }else if(cur == parent.left){
                //是父亲的左子树
                parent.left = cur.right;
            }else {
                //是父亲的右子树
                parent.right = cur.right;
            }
        }else if (cur.right == null){
            //没有右子树
            if (cur == root){
                //是根节点
                root = root.left;
            }else if(cur == parent.left){
                //是父亲节点的左子树
                parent.left = cur.left;
            }else {
                //是父亲节点的右子树
                parent.right = cur.right;
            }
        }else {
            //此时既有左又有右:去右边找最小值,也就是右子树的最左边
            TreeNode target = cur.right;
            TreeNode targetParent = cur;
            while (target.left != null){
                targetParent = target;
                target = target.left;
            }
            //找到了交换值
            cur.val = target.val;
            //删除target:处理特殊情况下面说明
            if(target == targetParent.left){
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }特殊情况:当去右子树里找最小值时,每一个子树没有左子树的时候,此时待删节点的右边第一个就是最小值,这种情况删除时需要注意
 
   


















