【Java数据结构】搜索二叉树——对节点的插入、查找、删除 操作(注释很详细我奶奶都能看懂)

30 篇文章 10 订阅
15 篇文章 4 订阅

📢博客主页:🏀敲代码的布莱恩特🏀
📢欢迎点赞 👍 收藏 ⭐留言 📝 欢迎讨论!👏
📢本文由 【敲代码的布莱恩特】 原创,首发于 CSDN🙉🙉🙉
📢由于博主是在学小白一枚,难免会有错误,有任何问题欢迎评论区留言指出,感激不尽!✨
📖精品专栏(不定时更新)【JavaSE】 【Java数据结构】【LeetCode
在这里插入图片描述

🛸搜索二叉树——基本概念

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

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

注意:二叉搜索树中没有重复的元素

如下图为一个二叉搜索树
在这里插入图片描述

🛸搜索二叉树——基本属性

二叉树是由一个一个节点组成的,先定义好节点的属性

代码实现:

public class Node{
        int key;//节点值
        Node left;//左孩子节点
        Node right;//右孩子节点

        public Node(int key){//重写一下节点的构造方法
            this.key = key;
        }
    }

    Node root = null;//一开始根节点为空

🛸搜索二叉树——查找节点

查找过程:

  1. 拿着待查元素和根节点比较;
  2. 如果比根节点小,继续在左子树中查找;
  3. 如果比根节点大,继续在右子树中查找;
  4. 如果当前元素查找到null也没找到,说明该元素不存在

在这里插入图片描述
代码实现:

/**
     * 在搜索树中查找 key,如果找到,返回 key 所在的结点,否则返回 null
     * @param key
     * @return
     */
    public Node search(int key){
        Node cur = root;//cur从root开始走
        while(cur != null){
            if(cur.key == key){//如果cur的值与key相等,则返回cur
                return cur;
            }else if(key > cur.key){//key值比cur的值大,cur往右节点走
                cur = cur.right;
            }else if(key < cur.key){//key值比cur的值小,cur往左节点走
                cur = cur.left;
            }
        }
        return null;//root为空,或者二叉树里没有这个节点,返回空值
    }

🛸搜索二叉树——插入节点

插入过程:

  1. 如果树是空树,即根== null,直接插入即可,返回true在这里插入图片描述
  2. 如果树不是空树,按照 查找逻辑(大的放左边,小的放右边) 确定插入位置,插入新结点
    注意:最后确定的插入位置一定是叶子节点

在这里插入图片描述

代码实现:

/**
     * 插入
     * @param key
     * @return true 表示插入成功, false 表示插入失败
     */
    public Boolean insert(int key){
        if(root == null){//如果根节点空,则第一个节点就是根节点
            root = new Node(key);
            return true;
        }

        Node cur = root;//用cur从root位置开始往下走
        Node parent = null;//需要用一个parent节点来记录上一个节点
        //通过while循环来找插入位置
        while(cur != null){
            if (key == cur.key){
                return false;//如果二叉树里已经有这个值,就无法插入
            }
            else if (key < cur.key){//key比cur的值小,说明要插到左边
                parent = cur;//记录上一个节点
                cur = cur.left;//cur往左走
            }
            else if (key > cur.key){//key比cur的值大,说明要插到右边
                parent = cur;//记录上一个节点
                cur = cur.right;//cur往右走
            }
        }
        //while走完了,说明是时候插入节点了,因为我们插入节点的位置一定是叶子节点的位置
        //这就需要用到parent了
        Node node = new Node(key);//创建要插入的新节点
        if (node.key > parent.key){//比parent值大放右边
            parent.right = node;
        }else {
            parent.left = node;//反之放左边
        }
        return true;//插入成功
    }

🛸搜索二叉树——删除节点

设待删除结点为 cur, 待删除结点的双亲结点为 parent,删除节点的关键在于对多种情况的分析

  1. cur.left == null 待删除节点只有右子树
    (这种情况下删哪个点,就将其右子树接到这个点的父节点后边
    在这里插入图片描述

  2. cur.right == null 待删除节点 只有左子树
    (这种情况下删哪个点,就将其左子树接到这个点的父节点后边
    在这里插入图片描述

  3. cur.left != null && cur.right != null 待删除节点左右子树都存在
    (需要使用替换法进行删除,即在它的右子树寻找最小值结点,用它的值填补到被删除节点中,再来处理该结点的删除问题,关键就在于这个寻找最小值替代这一步

在这里插入图片描述

总而言之,这第三种情况处理方法就是,从待删除点的右树里找最小值来替换待删除点,然后将替罪羊节点的右树接到替罪羊节点的父节点后边即可,注意点就是替罪羊节点是在父节点左边还是右边

代码实现:

/**
     * 删除成功返回 true,失败返回 false
     * @param key
     * @return
     */
    public void removeKey(int key) {
        if(root == null) {
            return;
        }
        Node cur = root;
        Node parent = null;
        while (cur != null) {
            if(cur.key == key) {
                remove(parent,cur);
                return;
            }else if(cur.key < key){
                parent = cur;
                cur = cur.right;
            }else {
                parent = cur;
                cur = cur.left;
            }
        }
    }

    private void remove(Node parent, Node cur) {
        if (cur.left == null){//删除只有右孩子的节点
            if (cur == root){//要删除的点是根节点
                root = cur.right;
            }
            else if (cur == parent.left){//要删除的点在父亲节点左边
                parent.left = cur.right;
            }
            else if (cur == parent.right){//要删除的点在父亲节点右边
                parent.right = cur.right;
            }
        }
        else if(cur.right == null){//删除只有左孩子的节点
            if(cur == root) {//要删除的点是根节点
                root = cur.left;
            }
            else if(cur == parent.left) {//要删除的点在父亲节点左边
                parent.left = cur.left;
            }
            else if(cur == parent.right){//要删除的点在父亲节点右边
                parent.right = cur.left;
            }
        }
        else {
            Node target = cur.right;
            Node targetParent = cur;
            //找替罪羊target,找右树的最小左子树
            while(target.left != null){
                targetParent = target;
                target = target.left;
            }
            cur.key = target.key;
            if(target == targetParent.left){//如果当前目标值是父节点的左孩子
                targetParent.left = target.right;//就把目标节点的右孩子接到父节点的左边
            }
            else if(target == targetParent.right){//如果当前目标值是父节点的右孩子
                targetParent.right = target.right;//就把目标节点的右孩子接到父节点的右边
            }
        }
    }

🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙
       ❤原创不易,如有错误,欢迎评论区留言指出,感激不尽❤
       ❤               如果觉得内容不错,给个三连不过分吧~        ❤
       ❤                            看到会回访~                                      ❤
🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙

  • 39
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 44
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的布莱恩特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值