实现二叉搜索树

一、概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若他的左子树不为空,则左子树上所有的节点值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

这就是一颗二叉搜索树
在这里插入图片描述
在这里实现二叉搜索树的插入查找删除
1.插入
这里的插入不考虑插入重复的节点,并且插入的位置一定是叶子节点

  • 如果是根节点直接插入
  • 定义一个节点cur来遍历,定义一个节点parent来保存父亲节点
  • 比当前节点大就咋右边,反之在左边
  • 最后看比父亲节点大还是小,大插在右边,小插在左边

2.查找
定义一个节点cur来遍历

  • 如果cur.val 等于 val 找到 返回 cur
  • 如果cur.val < val 在右边查找
  • 如果cur.val > val 在左边查找

3.删除
找到要删除的节点cur以及他的父亲节点parent
分为三种情况
第一种cur.left == null

在这里插入图片描述

  1. curroot,则 root = cur.right,因为cur.left== null
  2. cur 不是 rootcurparent.left,则 parent.left = cur.right
  3. cur 不是 rootcurparent.right,则 parent.right = cur.right

第二种cur.right == null
在这里插入图片描述

  1. curroot,则 root = cur.left
  2. cur 不是 rootcurparent.left,则 parent.left = cur.left
  3. cur 不是 rootcurparent.right,则 parent.right = cur.left

第三种cur.left != null && cur.right != null
需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题
cur都不为空的时候,实现删除的思路有两种
1.在左边找最大值target,替换cur,把target删除
2.在右边找最小值target,替换cur,把target删除
这里采用第二种,在右子树找最小值
找到的最小值有两种情况
1.targettargetParent是左孩子,就是targetParent的左不为空
2.targettargetParent是右孩子,就是target的左为空
在这里插入图片描述
因为是找最小值,所以target的左一定是空
targetParent的左或者右 指向 target的右

实现代码:

/**
 * @author PineappleSnow
 * @version 1.0
 * @date 2020/5/29 7:49
 */
public class BSTree {
    //定义内部类Node是节点
    public static class Node {
        public int val;
        public Node left;
        public Node right;

        public Node(int val) {
            this.val = val;
        }
    }

    //定义一个根节点
    Node root = null;

    /**
     * 插入
     * @param val
     * @return true 表示插入成功, false 表示插入失败
     */
    public boolean insert(int val) {
        Node node = new Node(val);
        if (root == null) {
            this.root = node;
            return true;
        }
        Node cur = root;
        Node parent = null;//需要保存cur的父亲节点,找到位置插入到父亲节点的后面
        while (cur != null) {
            if (cur.val < val) {//在右子树
                parent = cur;
                cur = cur.right;
            }else {//在左子树
                parent = cur;
                cur = cur.left;
            }
        }
        //cur为空  位置找到  进行插入
        //两种情况 在parent 的 左 或者 右
        //已经知道parent的位置 比较大小后插入
        if (parent.val < val) {//在右边
            parent.right = node;
        }else {//在左边
            parent.left = node;
        }
        return true;
    }

    //前序遍历
    public void preOrder(Node root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //中序遍历
    public void inOrder(Node root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

    /**
     * 在搜索树中查找val
     * @param val
     * @return Node 表示找到, null表示没找到
     */
    public Node search(int val) {
        if (root == null) {
            return null;
        }
        Node cur = root;
        while (cur != null) {
            if (cur.val == val) {
                return cur;
            }else if (cur.val < val) {
                cur = cur.right;
            }else {
                cur = cur.left;
            }
        }
        return null;
    }

    /**
     * 删除
     * @param key
     * @return true 删除成功, false 删除失败
     */
    public boolean remove(int key) {
        Node parent = null;//需要父亲节点
        Node cur = root;//这是要删除的节点
        while (cur != null) {
            if (cur.val == key) {//找到要删除的节点了
                doRemove(parent,cur);//执行删除操作
                return true;
            }else if (cur.val < key) {//在右边找
                parent = cur;
                cur = cur.right;
            }else {//在左边找
                parent = cur;
                cur = cur.left;
            }
        }
        return false;
    }

    //实现操作
    public void doRemove(Node parent, Node cur) {
        //分三种情况 cur的左为空 cur的右为空 cur的左右都不空
        if (cur.left == null) {//cur的左为空
            //分三种情况 cur是根节点 cur是parent的左 cur是parent的右
            if (cur == root) {
                root = cur.right;
            }else if (cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if (cur.right == null) {//cur的右为空
            //分三种情况 cur是根节点 cur是parent的左 cur是parent的右
            if (cur == root) {
                root = cur.left;
            }else if (cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {//cur的左右都不为空
            //当cur都不为空的时候,实现删除的思路有两种
            //1.在左边找最大值target,替换cur,把target删除
            //2.在右边找最小值target,替换cur,把target删除
            //这里采用第二种,在右子树找最小值
            Node targetParent = cur;//记录好父亲节点
            Node target = cur.right;//把target的值赋给cur,实际删除target,替罪羊节点
            while (target.left != null) {//最小值一定是在左边
                targetParent = target;
                target = target.left;
            }
            //进行赋值
            cur.val = target.val;
            //找到的最小值有两种情况
            //1.target是targetParent是左孩子,就是targetParent的左不为空
            //2.target是targetParent是右孩子,就是target的左为空
            //因为是找最小值,所以target的左一定是空
            //让targetParent的左或者右 指向 target的右
            if (target == targetParent.left) {
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }

}

测试代码:

/**
 * @author PineappleSnow
 * @version 1.0
 * @date 2020/5/29 8:03
 */
public class BSTreeTest {
    public static void main(String[] args) {
        BSTree bsTree = new BSTree();
        int[] array = {7,2,9,18,56,15,3};
        for (int i : array) {
            bsTree.insert(i);
        }
        bsTree.preOrder(bsTree.root);
        System.out.println();
        bsTree.inOrder(bsTree.root);
        System.out.println();
        System.out.println(bsTree.search(18).val);
        System.out.println("==========删除============");
        bsTree.remove(18);
        bsTree.preOrder(bsTree.root);
        System.out.println();
        bsTree.inOrder(bsTree.root);
        System.out.println();
    }
}

这是测试结果:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值