N
)
O(N)
O(N),AVL
树不一样,在10亿中只用找30次(可能多一点)
二. AVL树结点的定义
此处我们定义成三叉链结构 ,方便后序的操作;也在每个节点引入了平衡因子(右子树高度-左子树高度),还需要实现一下构造函数,左右子树以及父节点都是空,再把平衡因子设置为0即可
template<class K, class V>
struct AVLTreeNode
{
//定义三叉链
AVLTreeNode<K, V>\* _left;
AVLTreeNode<K, V>\* _right;
AVLTreeNode<K, V>\* _parent;
//存储的键值对
pair<K, V> _kv;
//平衡因子(balance factor)
int _bf;
//构造函数
AVLTreeNode(const pair<K, V>& kv)
:\_left(nullptr)
,\_right(nullptr)
,\_parent(nullptr)
,\_kv(kv)
,\_bf(0)
{}
};
注意:平衡因子不是必须的,只是我们实现高度平衡的一种方式,不用平衡因子也是可以实现的
三. AVL树的插入
插入节点有三个步骤
- 按照二叉搜索树的原理,找到待插入的位置
- 判断待插入的节点是在parent的左还是右,插入节点
- 更新平衡因子,如果发现不平衡,则要旋转
🔥因为AVL树本身就是一颗二叉搜索树,插入规则(比较节点大小即可):
- 插入的节点key值
>
当前位置的key值,插入到右子树 - 插入的节点key值
<
当前位置的key值,插入到左子树 - 插入的节点key值等于当前位置的key值,插入失败
🌈那判断完插入成功与否,是不是就要判断平衡因子的更新了
平衡因子是否更新取决于:该结点的左右子树的高度是否发生了变化,因此插入一个结点后,该结点的 祖先结点的平衡因子可能需要更新
🌏更新平衡因子的规则:
- 新增在右,parent ->
bf++
;新增在左,parent ->bf --
;
每更新完一个结点的平衡因子后,都需要进行以下判断:
- 如果parent的平衡因子等于-1或者1,表明还需要继续往上更新平衡因子
- 如果parent的平衡因子等于0;表明无需往上更新平衡因子
- 如果parent的平衡因子等于-2或者2;就已经不平衡了,需要旋转处理
- 如果parent的平衡因子大于2或者小于-2;就说明之前插入的就不是AVL树了,赶紧去检查💥
更新后的平衡因子 | 分析 |
---|---|
-1 or 1 | 说明parent插入前的平衡因子是0;左右子树高度相等,插入后有一边高,parent高度变了,则需要往上继续更新 |
0 | 说明parent插入前的平衡因子是 -1 or 1;左右子树一边高一边低,插入后两边相等,插入的填上了矮的那一边,parent的高度不变,不需要继续往 |