二叉查找树(三):插入和分析
1. 基本实现(二):插入 - put()
在进入插入操作的讲解之前,大家可以思考这么一个问题:
插入和查找究竟有什么区别呢?
其实两者的区别不是特别大,对于插入操作,我们也需要知道插入到哪里?而这个过程就是查找的过程。等找到了插入的位置了,那就简单了,我们只需要在这个位置插入新的节点,并从下至上(Bottom-up)更新每个节点的节点数即可。
那么我们把上节中 查找 - get() 的伪代码拿过来:
- 如果当前root.key < key,则所查找的key应该在root的右子树,因为右子树的所有节点都大于root;
- 相反如果当前的root.key > key,则所查找的key应该在root的左子树,因为左子树的所有节点都小于root;
- base case(返回条件)则有两种:1)当root.key == key,在BST中找到key,则返回root.val;2)root == null,则BST中没有找到key,则返回null;
我们可以注意到,对于 插入 - put() ,我们只需要修改base case就可以了:
- 如果当前root.key < key,则所插入的key应该在root的右子树,因为右子树的所有节点都大于root;
- 相反如果当前的root.key > key,则所插入的key应该在root的左子树,因为左子树的所有节点都小于root;
- 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. 特别感谢
- 感谢 @SENNICHEN 制作系列文章封面图
4. 免责声明
※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;