AVL树性质
- 它的左右子树都是AVL树
- 左右子树高度之差的绝对值不超过1(右子树高度 - 左子树高度)(也称为平衡因子)
- 每个节点都有一个平衡因子
- 一般AVL树都是三叉链(左右节点指针和父亲节点指针)
- AVL树高度为 O(logN)
- AVL树的时间复杂度为O(logN)。
平衡因子的更新原则:
- 如果新增节点在父节点的左边,则父节点的平衡因子减1;依次向上更新
- 如果新增节点在父节点的右边,则父节点的平衡因子加1;依次向上更新
- 直到当前节点的平衡因子为0才不向上继续更新了
- 如果平衡因子为-2或2,则需要旋转。然后在判断是否需要继续更新。
AVL树节点的定义方式
template<class K,class V>
struct AVLTreeNode //建立节点
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf; //平衡因子
pair<K, V> _kv; //键值对,存储数据
AVLTreeNode(const pair<K, V>& kv) //构造函数
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
,_kv(kv)
{}
};
AVL树的四种旋转方式
为什么要旋转
- 当插入一个节点时,直接插入可能会导致平衡被破坏(插入节点的所有祖先节点的平衡因子可能会改变)
- 这时就需要将数据进行旋转
- 例如:当插入 30 节点时,这个树就不是AVL树了,所以将其进行旋转,得到右边的AVL树。
右单旋
右单旋代码实现
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parent_parent = parent->_parent;
parent->_left = subLR;
if (subLR) subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent_parent->_left == parent) parent_parent->_left = subL;
else parent_parent->_right = subL;
subL->_parent = parent_parent;
}
subL->_bf = 0;
parent->_bf = 0;
}
左单旋
左单旋代码实现
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parent_parent = parent->_parent;
parent->_right = subRL;
if (subRL) subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent_parent->_left == parent)parent_parent->_left = subR;
else parent_parent->_right = subR;
subR->_parent = parent_parent;
}
subR->_bf = 0;
parent->_bf = 0;
}
左右双旋
左右双旋代码实现
//左右双旋
void LRrotate(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
subLR->_bf = 0;
}
else if (bf == 1)
{
subL->_bf = -1;
parent->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 0)
{
subL->_bf = 0;
parent->_bf = 0;
subLR->_bf = 0;
}
else
{
assert(false);
}
}
右左双旋
原理同上。
//右左双旋
void RLrotate(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
subRL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subR->_bf = 0;
subRL->_bf = 0;
}
else
{
assert(false);
}
}
源码地址
gitee地址:https://gitee.com/BJFyfwl/Lin...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。