二叉搜索树的操作及其实现

ced485cbb11e458d81a746890b32cf3f.gif 

作者:渴望力量的土狗

博客主页:渴望力量的土狗的博客主页

专栏:数据结构与算法

工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器——牛客网

点击免费注册和我一起刷题吧

目录

二叉搜索树的概念:

二叉搜索树的操作及其实现


二叉搜索树的概念:

二叉搜索树是一种特殊的二叉树,要么是一颗空树,要么满足以下几点:

1、 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

2、若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

3、它的左右子树也分别为二叉搜索树

下面就是一颗典型的二叉搜索树:

 

二叉搜索树的操作及其实现

二叉搜索树的查找效率是比较高的,类似与我们所熟知的二分查找。它的查找方式是这样的:如果我们要查找6这个数字,那么我们从根节点开始,遇到根节点的val是5,6>5,所以我们要往右搜寻,遇到7的时候,6<7,这时我们向右左找即可,这就找到了我们要找的数字。

我们可以看的出它的时间复杂度是O(logn),也就是搜索树的高度,但是,如果这颗搜索树呈现线性的化,也就是一条线的情况:

这时我们在搜索的时候就类似于线性查找,时间复杂度就达到了O(n)了。

然后就是二叉搜索树的插入操作,我们怎么把数据插入到原来的二叉搜索树当中呢?插入的操作和查找有点类似,需要搜索到需要查找的位置。具体逻辑为:当树空的时候直接new一个结点即可,不空的情况下,当我们要插入一个元素的时候我们需要知道它的前一个元素,这样我们才能实现插入操作,插入的位置都是为空的,所以我们要查找到它适合的位置即可。

二叉搜索树的删除属于最重要的内容,因为它的删除操作可能比较复杂一点,我们在删除某一个结点的时候需要调整,你怎么知道调整后是什么样子的呢?删除前我们还是要进行搜索,找到待删除结点的位置。

这里先说一下删除的步骤:

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

一. cur.left == null (要删除结点的左边为空时)

1. cur 是 root,则 root = cur.right

2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right

3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right

 

二. cur.right == null (要删除结点的右边为空时)

1. cur 是 root,则 root = cur.left

2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left

3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left

 

三. cur.left != null && cur.right != null

1. 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被 删除节点中,再来处理该结点的删除问题

下面对二叉搜索树进行实现:

public class BinarySearchTree {

    static class TreeNode {
        public int key;
        public TreeNode left;
        public TreeNode right;

        TreeNode(int key) {
            this.key = key;
        }
    }

    public TreeNode root;

    /**
     * 插入一个元素
     * @param key
     */
    public boolean insert(int key) {
        //根结点
        if(root==null){
            root=new TreeNode(key);
            return true;
        }

        //找到需要插入的位置
        TreeNode cur=root;//找位置
        TreeNode parent=cur;//插入位置的父节点
        while(cur!=null){
            if(cur.key<key){
                parent=cur;
                cur=cur.right;
            } else if (cur.key>key) {
                parent=cur;
                cur=cur.left;
            }else{
                //不可以插入相同的元素
                return false;
            }
        }
        //此时cur为空了,这个位置就是插入的位置
        //这里需要讨论插入到parent的左边还是右边
        if(key> parent.key){
            //插入右边
            parent.right=new TreeNode(key);
        }else{
            //插入左边
            parent.left=new TreeNode(key);
        }
        return true;
    }

    /**
     * 查找key是否存在
     * @param key
     * @return
     */
    public TreeNode search(int key) {
       TreeNode cur=root;

       //我们搜索的最差情况为当前结点为空
        while (cur!=null){

            //先判断根结点
            if(cur.key==key){
                return cur;
                //如果key比结点的key大向右找
            } else if (cur.key<key) {
                cur=cur.right;
                //如果key比结点的key小向左找
            } else {

                cur=cur.left;
            }
        }
        //如果cur为空则返回空
        return null;
    }
    //中序遍历
    public void inOrder(TreeNode root){

        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.key+" ");
        inOrder(root.right);


    }


    /**
     * 删除key的值
     * @param key
     * @return
     */
    public void remove(int key) {

        TreeNode parent = null;
        TreeNode cur = root;
        while (cur != null) {
            if(cur.key == key) {
                removeNode(parent,cur);
                return;
            }else if(cur.key < key) {
                parent = cur;
                cur = cur.right;
            }else {
                parent = cur;
                cur = cur.left;
            }
        }
    }

    private void removeNode(TreeNode parent,TreeNode cur) {
        if(cur.left == null) {
            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) {
            if(cur == root) {
                root = cur.left;
            } else if (cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            TreeNode target = cur.right;
            TreeNode targetParent = cur;
            while (target.left != null) {
                targetParent = target;
                target = target.left;
            }
            cur.key = target.key;
            if(target == targetParent.left) {
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }


}
  • 94
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

渴望力量的土狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值