一、概念
AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度。
二、性质
- 树中每个左子树和右子树都是AVL树
- 左子树和右子树高度之差的绝对值(简称平衡因子)不超过1(0,1,-1)
平衡因子就是用右子树的高度减去左子树的高度
红色的就是每个节点的平衡因子
三、AVL树的插入
如果在一棵原本是平衡的二叉搜索树中插入一个新节点,可能造成不平衡,此时必须调整树 的结构,使之平衡化。
插入算法:
- 如果是空树,插入后即为根节点,插入后直接返回true
- 如果树不空,寻找插入位置,若在寻找的过程中找到key,则插入失败直接返回false
- 插入结点
- 更新平衡因子,对树进行调整
新节点pcur平衡因子为0,但其双亲结点parent的平衡因子有三种情况:
如果parent的平衡因子为0
即在parent较矮的子树上插入新节点,parent平衡,其高度没有增加,此时从parent到 根路径 上各结点为根的子树的高度不变,即各结点的平衡因子不变,结束平衡化处理。如果parent的平衡因子的绝对值为1
插入前parent的平衡因子为0,插入后以parent为根的子树没有失去平衡,但该子树 的高度增 加,需从parent向根节点方向回溯,继续查看parent的双亲的平衡性。- 在上述更新后,如果parent平衡因子的绝对值为2,新节点在较高的子树插入,需要做平衡化处理:
若parent->_bf == 2,说明右子树高,设parent的右子subR
当subR的平衡因子为1,执行左单旋转
当subR的平衡因子为-1,执行先右后左双旋转
若parent->_bf == -2,说明左子树高,设parent的左子树subL
当subL的平衡因子为-1,执行右单旋转
当subL的平衡因子为1,执行先左后右双旋转
旋转后parent为根的子树高度降低,无需继续向上层回溯
1.左单旋
插入节点位于较高右子树的右侧
如下图所示:
//左单旋
void RotateL(pNode parent)
{
pNode subR = parent->_pRightChild;
pNode subRL = subR->_pLeftChild;
parent->_pRightChild = subRL;
if (subRL)
subRL->_pParent = parent;
subR->_pLeftChild = parent;
pNode pparent = parent->_pParent;
subR->_pParent = pparent;
parent->_pParent = subR;
if (parent == _pRoot)
{
_pRoot = subR;
}
else//更新祖父节点的左右孩子
{
if (pparent->_pLeftChild == parent)
pparent->_pLeftChild = subR;
else
pparent->_pRightChild = subR;
}
//更新平衡因子
parent->_bf = subR->_bf = 0;
}
2.右单旋
插入节点位于较高左子树的左侧
如下图所示:
void RotateR(pNode parent)
{
pNode subL = parent->_pLeftChild;
pNode subLR = subL->_pRightChild;
parent->_pLeftChild = subLR;
if (subLR)
subLR->_pParent = parent;
subL->_pRightChild = parent;
pNode pparent = parent->_pParent;
parent->_pParent = subL;
subL->_pParent = pparent;
if (parent == _pRoot)
{
_pRoot = subL;
}
else
{
if (pparent->_pLeftChild ==