1. AVL树的定义
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
2. 节点定义
struct AVLNode
{
AVLNode(const T& data)
:_data(data)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
{}
T _data;
AVLNode<T>*_left;
AVLNode<T>*_right;
AVLNode<T>*_parent;
int _bf;
};
3.四种旋转
3.1 右单旋
来看下面的情况
在x处插入节点,导致平衡因子 = h+1+1+1 - h -1 = 2,处于失衡状态。这个时候就要向右边旋转,重新达到平衡,在以上的demo里,我们处理的过程是,拿到x的父节点b,使b节点作为父节点,b的父节点a成为b的右孩子节点,b的右孩子节点成为a的左孩子。
调整后:
void RotateRight(pNode parent) //右单旋
{
pNode subL = parent->_left;
pNode subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
if (parent != _root)
{
if (parent->_parent->_left == parent)
parent->_parent->_left = subL;
else
parent->_parent->_right = subL;
subL->_parent = parent->_parent;
}
else
{
_root = subL;
subL->_parent = nullptr;
}
parent->_parent = subL;
subL->_bf = parent->_bf = 0;
}
3.2 左单旋
左单旋和上述例子刚好相反,即插入新的节点使右边比左边高,向左旋转,这里不再赘述过程,只演示调整结果。
调整前:
调整后:
void RotateLeft(pNode parent) //左单旋
{
pNode subR = parent->_right;
pNode subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
if (parent != _root)
{
if (parent->_parent->_left == parent)
parent->_parent->_left = subR;
else
parent->_parent->_right = subR;
subR->_parent = parent->_parent;
}
else
{
_root = subR;
subR->_parent = nullptr;
}
parent->_parent = subR;
subR->_bf = parent->_bf = 0;
}
3.3 先左旋转后右旋转
来看以下情况:
先对局部进行左旋转
再整体进行右旋转
3.4 先右旋转再左旋转
与上述情况刚好相反,只演示调整:
4. 判断是否平衡
保证不存在平衡因子绝对值超过或者等于2即可
bool IsBanlance(pNode root) //判断树是否平衡
{
if (root == nullptr)
return true;
int leftH = Height(root->_left);
int rightH = Height(root->_right);
if (root->_bf != (rightH - leftH))
return false;
return abs(root->_bf) < 2
&& IsBanlance(root->_left)
&& IsBanlance(root->_right);
}