Java数据结构学习DAY8——搜索树和哈希表(二)

5. 搜索树

5.1 概念

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

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

在这里插入图片描述

                     int a [] = {5,3,4,1,7,8,2,6,0,9};

5.2 操作-查找

在这里插入图片描述

  • 代码实现
    //1、查找
    //空树用 null 表示
    BinaryNode root = null;

    public Integer get(int key) {

        BinaryNode  cur = root;
        //创建一个引用 cur 从根节点出发
        //当树非空时,判断 key 和 cur.key的值,再决定走哪个方向
        while(cur != null) {
            if (key < cur.key) {
                //往左子树走
                cur= cur.left;
            } else if (key > cur.key) {
                cur = cur.right;
            } else {
                //找到了
                return cur.key;
            }
        }
        //若遍历完循环出来都没找到说明没有找到
        return null;
    }

5.3 操作-插入

  1. 如果树为空树,即根 == null,直接插入

在这里插入图片描述

  1. 如果树不是空树,按照查找逻辑确定插入位置,插入新结点

在这里插入图片描述

  1. 代码实现
    //2、插入
    //让 cur 从根节点开始出发,找到一个合适的插入位置
    public void put(int key, int value) {
        if (root == null) {
            //直接把新节点挂到 root 上即可
            root = new BinaryNode(key,value);
            return;
        }
        
        //创建一个 cur 从 root 出发,找到 一个合适的插入位置。
        BinaryNode  cur = root;
        BinaryNode  parent = null;//记录 cur 的父节点,
        while (cur !=null) {
            if(key < cur.key){
                parent = cur;
                cur = cur.left;
            }else if (key > cur.key) {
                parent = cur;
                cur = cur.right;
            } else {
                //当 key 相同时,并不真的插入新节点
                //而是用 value 来替换旧的节点的值
                cur.value = value;
                return;
            }
        }

        //当循环结束 cur 为空,说明已经找到了要插入的位置
        //cur 为空的时候就说明新节点要插入到parent下面
        BinaryNode newNode = new BinaryNode(key,value);
        if (newNode.key < parent.key) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }
    }

5.4 操作-删除

5.4.1 删除节点情况讨论

设待删除结点为 cur, 待删除结点的双亲结点为 parent

  1. cur.left == null
    1.1 cur 是 root,则 root = cur.right
    在这里插入图片描述

1.2 cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
在这里插入图片描述

1.3 cur 不是 root,cur 是 parent.right,则 parent.right = cur.right
在这里插入图片描述

  1. cur.right == null
    2.1 cur 是 root,则 root = cur.left
    在这里插入图片描述
    2.1 cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
    在这里插入图片描述
    2.3 cur 不是 root,cur 是 parent.right,则 parent.right = cur.left
    在这里插入图片描述

  2. cur.left != null && cur.right != null
    需要使用替换法(移形换影)进行删除,在cur的右子树里找出最小值或者在cur的左子树里找出最大值.
    在这里插入图片描述

5.4.2 删除代码实现

    //3、删除节点
    public void remove(int key){
        //1.先查找待删除节点的位置,也需要同步记录该节点的父节点信息
        BinaryNode cur = root;
        BinaryNode parent = null;
        while (cur != null) {
            if (key < cur.key) {
                //往左走
                parent = cur;
                cur = cur.left;
            } else if (key >cur.key) {
                //往右走
                parent = cur;
                cur = cur.right;
            } else {
                //key 相等,找到了待删除节点
                //2.key 相等,找到了待删除节点
                removeNode(parent,cur);
                return;
            }
        }
    }
    //由于当前的 removeNode 方法只是给类自己的 remove 方法来使用的
    //没有其他用途了,所以不应该暴露到类的外部
    private void removeNode(BinaryNode parent,BinaryNode cur) {
        if(cur.left == null){
            //1.待删除节点的左子树为null
            if(cur == root ){
                //待删除节点正是根节点
                root = cur.right;
            } else if (cur == parent.left) {
                //1.2 待删除节点不是树根,且是父亲的左子树
                parent.left = cur.right;
            } else if (cur == parent.right) {
                //1.3 待删除节点不是树根且,是父亲的右子树
            }
        } else if (cur.right == null) {
            //2.待删除节点的右子树为 null
            if (cur == null) {
                //2.1 待删除节点正是根节点
                root = cur.left;
            } else if (cur == parent.left) {
                //2.2 待删除节点不是根节点,且为父亲的左子树
                parent.left = cur.left;
            } else if (cur == parent.right) {
                //2.3 待删除节点不是根节点,且为父亲的右子树
                parent.right = cur.left;
            }
        } else {
            //3.左右子树都存在的情况
            //  需要在右子树中找到最小值,作为替罪羊节点
            //  把替罪羊节的 key 和 value 赋值给待删除节点
            //  删除替罪羊节点即可
            BinaryNode goat = cur.right;
            BinaryNode goatParengt = cur;
            while (goat.left != null) {
                goatParengt = goat;
                goat = goat.left;
            }
             cur.key = goat.key;
             cur.value = goat.value;
             //删除替罪羊节点,根据替罪羊是左右子树来采取不同的删除方式
            if (goat == goatParengt.left) {
                goatParengt.left = goat.left;
            } else {
                goatParengt.right = goat.right;
            }
         }
    }

二叉搜索树基础操作的完整代码

package Java42_0328;


class BinaryNode {
    public int key;
    public int value;
    public BinaryNode left;
    public BinaryNode right;

    public BinaryNode(int key, int value) {
        this.key = key;
        this.value = value;

    }
}
public class BinarySearchTree {

    //1、查找
    //空树用 null 表示
    private BinaryNode root = null;

    public Integer get(int key) {

        BinaryNode  cur = root;
        //创建一个引用 cur 从根节点出发
        //当树非空时,判断 key 和 cur.key的值,再决定走哪个方向
        while(cur != null) {
            if (key < cur.key) {
                //往左子树走
                cur= cur.left;
            } else if (key > cur.key) {
                cur = cur.right;
            } else {
                //找到了
                return cur.key;
            }
        }
        //若遍历完循环出来都没找到说明没有找到
        return null;
    }

    //2、插入
    //让 cur 从根节点开始出发,找到一个合适的插入位置
    public void put(int key, int value) {
        if (root == null) {
            //直接把新节点挂到 root 上即可
            root = new BinaryNode(key,value);
            return;
        }

        //创建一个 cur 从 root 出发,找到 一个合适的插入位置。
        BinaryNode  cur = root;
        BinaryNode  parent = null;//记录 cur 的父节点,
        while (cur !=null) {
            if(key < cur.key){
                parent = cur;
                cur = cur.left;
            }else if (key > cur.key) {
                parent = cur;
                cur = cur.right;
            } else {
                //当 key 相同时,并不真的插入新节点
                //而是用 value 来替换旧的节点的值
                cur.value = value;
                return;
            }
        }

        //当循环结束 cur 为空,说明已经找到了要插入的位置
        //cur 为空的时候就说明新节点要插入到parent下面
        BinaryNode newNode = new BinaryNode(key,value);
        if (newNode.key < parent.key) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }
    }




    //3、删除节点
    public void remove(int key){
        //1.先查找待删除节点的位置,也需要同步记录该节点的父节点信息
        BinaryNode cur = root;
        BinaryNode parent = null;
        while (cur != null) {
            if (key < cur.key) {
                //往左走
                parent = cur;
                cur = cur.left;
            } else if (key >cur.key) {
                //往右走
                parent = cur;
                cur = cur.right;
            } else {
                //key 相等,找到了待删除节点
                //2.key 相等,找到了待删除节点
                removeNode(parent,cur);
                return;
            }
        }
    }
    //由于当前的 removeNode 方法只是给类自己的 remove 方法来使用的
    //没有其他用途了,所以不应该暴露到类的外部
    private void removeNode(BinaryNode parent,BinaryNode cur) {
        if(cur.left == null){
            //1.待删除节点的左子树为null
            if(cur == root ){
                //待删除节点正是根节点
                root = cur.right;
            } else if (cur == parent.left) {
                //1.2 待删除节点不是树根,且是父亲的左子树
                parent.left = cur.right;
            } else if (cur == parent.right) {
                //1.3 待删除节点不是树根且,是父亲的右子树
            }
        } else if (cur.right == null) {
            //2.待删除节点的右子树为 null
            if (cur == null) {
                //2.1 待删除节点正是根节点
                root = cur.left;
            } else if (cur == parent.left) {
                //2.2 待删除节点不是根节点,且为父亲的左子树
                parent.left = cur.left;
            } else if (cur == parent.right) {
                //2.3 待删除节点不是根节点,且为父亲的右子树
                parent.right = cur.left;
            }
        } else {
            //3.左右子树都存在的情况
            //  需要在右子树中找到最小值,作为替罪羊节点
            //  把替罪羊节的 key 和 value 赋值给待删除节点
            //  删除替罪羊节点即可
            BinaryNode goat = cur.right;
            BinaryNode goatParengt = cur;
            while (goat.left != null) {
                goatParengt = goat;
                goat = goat.left;
            }
             cur.key = goat.key;
             cur.value = goat.value;
             //删除替罪羊节点,根据替罪羊是左右子树来采取不同的删除方式
            if (goat == goatParengt.left) {
                goatParengt.left = goat.left;
            } else {
                goatParengt.right = goat.right;
            }
        }
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值