作者:小 琛
欢迎转载,请标明出处
AVL树的概念与定义
二叉搜索树在很大程度上优化了查找的效率,但如果插入的数据非常有序(例如下图),则二叉搜索树就会退化成单一的链式结构,这种情况下的查找等操作就非常消耗时间。平衡二叉树就因此引入。
定义
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),实现降低树的高度,从而减少平均搜索长度。
对于每个节点的平衡因子值_bf,_bf=右子树高度-左子树高度。因此在一棵树的左边插入,平衡因子减一;右边插入平衡因子加一。
即一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树的高度差(通常称之为平衡因子)绝对值<=1.
AVL树的插入
步骤:
- 按照二叉搜索树的规则进行插入
- 调整平衡因子。
- 检查平衡因子是否合理,如果不合理进行调整
二叉搜索树的插入之前博客有讲,这里不进行赘述,直接从插入后的情况进行分析。
插入后的三种情况
- 情况1:
- 情况2:
- 情况3:
对于上面的三种情况,前两种满足AVL树的准则(高度差不大于1),而第三种,即不符合,这时候就需要进行"旋转调整"
四种不同情况下的旋转调整
- 右单旋
新节点插入较高左子树的左侧
旋转后结果:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppNode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_bf = subL->_bf = 0;
}
- 左单旋
新节点插入较高右子树的右侧
调整后结果:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppNode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else {
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
subR->_bf = parent->_bf = 0;
}
- 先左旋再又旋
新节点插入较高左子树的右侧
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
- 先右旋再左旋
新节点插入较高右子树的左侧
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
AVL树的评价
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保查询时高效的时间复杂度。
但是如果要对AVL树做一些结构修改的操作,性能非常低下。
比如:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但如果一个结构经常修改,就不太适合。
实现AVL树的总代码
#pragma once;
#include <iostream>
template <class K,class V>
struct AVLTreeNode
{
std::pair<K, V> _kv;
int _bf;// balance factor
AVLTreeNode<K, V>* _parent;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode(const std::pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
, _kv(kv)
{}
};
template <class K,class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
bool Insert(std::pair<K, V>& kv)
{
//依照二叉搜索树的规则插入
//空树的插入
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
//非空树插入
Node* cur = _root;
Node* parent = nullptr;//记录父节点
//寻找插入的位置
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)
{
cur->_parent = parent;
parent->_left = cur;
}
else
{
cur->_parent = parent;
parent->_right = cur;
}
//更新平衡因子
while (parent)
{
if (parent->_left == cur)
parent->_bf--;
else if (parent->_right == cur)
parent->_bf++;
if (parent->_bf == 0)
break;
else if (std::abs(parent->_bf) == 1)
{
cur = parent;
parent->_parent;
}
else if (std::abs(parent->_bf) == 2)
{
// 说明parent子树已经不平衡,需要旋转处理,让他平衡
if (parent->_bf == 2)
{
if (cur->_bf == 1)
{
RotateL(parent);
}
else if (cur->_bf == -1)
{
RotateRL(parent);
}
}
else if (parent->_bf == -2)
{
if (cur->_bf == -1)
{
RotateR(parent);
}
else if (cur->_bf == 1)
{
RotateLR(parent);
}
}
break;
}
else
{
return false;
}
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppNode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else {
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
subR->_bf = parent->_bf = 0;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppNode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_bf = subL->_bf = 0;
}
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
private:
Node* _root = nullptr;
};