二叉查找树(三):插入和分析

1. 基本实现(二):插入 - put()

在进入插入操作的讲解之前,大家可以思考这么一个问题:

插入和查找究竟有什么区别呢?

其实两者的区别不是特别大,对于插入操作,我们也需要知道插入到哪里?而这个过程就是查找的过程。等找到了插入的位置了,那就简单了,我们只需要在这个位置插入新的节点,并从下至上(Bottom-up)更新每个节点的节点数即可。

那么我们把上节中 查找 - get() 的伪代码拿过来:

  1. 如果当前root.key < key,则所查找的key应该在root的右子树,因为右子树的所有节点都大于root;
  2. 相反如果当前的root.key > key,则所查找的key应该在root的左子树,因为左子树的所有节点都小于root;
  3. base case(返回条件)则有两种:1)当root.key == key,在BST中找到key,则返回root.val;2)root == null,则BST中没有找到key,则返回null;

我们可以注意到,对于 插入 - put() ,我们只需要修改base case就可以了:

  1. 如果当前root.key < key,则所插入的key应该在root的右子树,因为右子树的所有节点都大于root;
  2. 相反如果当前的root.key > key,则所插入的key应该在root的左子树,因为左子树的所有节点都小于root;
  3. base case(返回条件)则有两种:1)当root.key == key,在BST中找到key,则更新root.val;2)root == null,则BST中没有找到key,则返回新建的节点;

还是不太能理解的童鞋,可以看看下面图例1来加深印象:

在这里插入图片描述

那么相应的代码也不成问题啦哒,代码结构和查找 - get() 非常相似:

    /**
     * update the number of children that the root has
     * */

    protected MapTreeNode<K, V> updateSize( MapTreeNode<K, V> root ) {
        root.numberOfChildren = size( root.left ) + size( root.right ) + 1;
        return root;
    }
    
    /**
     * put key -> val into this BST
     * */

    public void put( K key, V val ) {
        root = put( root, key, val );
    }

    private MapTreeNode<K, V> put( MapTreeNode<K, V> root, K key, V val ) {
        // base case, attach the new node to this position
        if ( root == null ) return new MapTreeNode<K, V>( ID++, key, val );

        int res = compareKeys( root, key );
        // the node should be attached in the left subtree
        if ( res > 0 ) root.left =  put( root.left, key, val );
        // the node should be attached in the right subtree
        else if ( res < 0 ) root.right = put( root.right, key, val );
        // added before, update value
        else root.val = val;

        return updateSize( root );
    }

最后我们使用二叉查找树的标准索引用例轨迹1,来完整看看整个插入操作的流程,大家也可以把这个例子作为练习,检验一下自己的掌握程度:

在这里插入图片描述

2. 分析

这部分的分析仅作简单的BST分析,不涉及过于复杂的分析,有兴趣的童鞋,可以参考一下教材这部分对应的内容:3.2.2 分析1

这里着重关注的是BST的最好、平均和最差情况。最好情况下,BST的结构非常的匀称,也就是一棵完整二叉搜索树(Complete Binary Search Tree):1

在这里插入图片描述
而一般情况,BST的结构接近完美情况:1

在这里插入图片描述
最后是最差情况,这种结构的BST和一个数组是没有任何区别的:1

在这里插入图片描述
通过上面图例的直观认识,我们可以推测,完美情况的BST的查找和搜索时间是O(logn),一般情况的BST接近O(logn),但最差情况的BST退化到O(n)。当数据量非常巨大的时候,O(n)的时间效率也是非常慢的,这个我们会在BST和红黑树的性能测试中,进行直观的感受。

讲解进行到这里,想必大家到BST有了一定程度的认识和了解,那么接下来,我们将进入BST中比较难的 删除 - delete() 的讲解。


上一节:二叉查找树(二):大小和查找
下一节:二叉查找树(四):删除和性能分析
系列汇总:超详细!红黑树详解文章汇总(含代码)

3. 特别感谢

  1. 感谢 @SENNICHEN 制作系列文章封面图

4. 免责声明

※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;


在这里插入图片描述


  1. Algorithms 4th Edition ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值