1、搜索二叉树可能会出现一边树很长另一边树很短的极端情况,这样的话二叉树就会退化,这时我们就引出了AVL树这样的改良版。AVL树会控制两端树的高度差的绝对值小于1。(一般为右数高度减左树高度)
2、AVL树会通过平衡因子来控制,因为是右-左,所以插入左边平衡因子--,右边则++
3、基本结构:
其中_parent是用来找上一节点进行链接
控制AVL的行为:
其中除了插入函数其余函数与搜索二叉树相似。
4、插入函数:
bool Insert(const pair<K, V>& kv)
{
//若头结点为空则直接加
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
//kv.first相当于BST中的k
//比较找插入的位置
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//找到插入的父节点
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
//插入链接
cur->_parent = parent;
// 更新平衡因子
while (parent)
{
//左--,右++
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
//根据parent的平衡因子来判断是否向上更新
//为0结束
if (parent->_bf == 0)
{
break;
}
//为1/-1
else if (parent->_bf == 1 || parent->_bf == -1)
{
// 继续往上更新
cur = parent;
parent = parent->_parent;
}
//为2/-2,违背规则旋转处理
else if (parent->_bf == 2 || parent->_bf == -2)
{
// 不平衡了,旋转处理
if (parent->_bf == 2 && cur->_bf == 1)
{
//左单旋
RotateL(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
//右单旋
RotateR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
//先右后左
RotateRL(parent);
}
else
{
//先左后右
RotateLR(parent);
}
break;
}
//若出错则报错
else
{
assert(false);
}
}
return true;
}
左单旋:
这里子树的高度为h,h分为0和>=1
h==1:
h>=1
转完后,改变parent节点,若subRL为空则不链接parent,不为空则链接
还有parent的parent为空则:
若不为空,parent在其父节点的左则向左链接,右同理:
更新平衡因子:
右单旋:
与左单旋相似:
平衡因子的更新: