我们知道,树的高度越小,查找速度越快。因此,希望二叉树的高度足够小。今天我们来看一种特殊类型的二叉搜索树——AVL平衡二叉树。在这种类型的树中,二叉树结构近乎平衡。
1. AVL树的定义
AVL树是具有如下特征的二叉搜索树:
(1)根的左子树和右子树的高度之差的绝对值不大于1;
(2)根的左子树和右子树都是AVL树。
2. AVL树的插入(Insert)
要在一棵二叉平衡树中插入一个新的结点,首先要查找结点要插入的位置。如果要插入的结点在二叉平衡树中,则查找到某一空子树处结束;否则,将新结点插入在二叉平衡树中。
在插入新结点后,可能会破会二叉平衡树的结构,此时,我们需要根据情况对二叉树进行调整。
(1)在较高右子树的右侧插入新结点——左旋
void RotateL(PNode parent)
{
PNode pSubR = parent->_PRight;
PNode pSubRL = pSubR->_PLeft;
parent->_PRight = pSubRL;
if (pSubRL)
pSubRL->_pParent = parent;
pSubR->_PLeft = parent;
PNode Pparent = parent->_pParent;
parent->_pParent = pSubR;
pSubR->_pParent = Pparent;
if (parent == _PRoot)
_PRoot = pSubR;
else
{
if (Pparent->_PLeft == parent)
Pparent->_PLeft = pSubR;
else
Pparent->_PRight = pSubR;
}
parent->_bf = 0;
pSubR->_bf = 0;
}
(2)在较高左子树的左侧插入新结点——右旋
右旋和左旋的两种考虑情况相似,我们可以自己画图分析分析。
void RotateR(PNode parent)
{
PNode pSubL = parent->_PLeft;
PNode pSubLR = pSubL->_PRight;
parent->_PLeft = pSubLR;
if (pSubLR)
pSubLR->_pParent = parent;
pSubL->_PRight = parent;
PNode Pparent = parent->_pParent;
parent->_pParent = pSubL;
if (parent == _PRoot)
_PRoot = pSubL;
else
{
if (Pparent->_PLeft == parent)
Pparent->_PLeft = pSubL;
else
Pparent->_PRight = pSubL;
}
pSubL->_pParent = Pparent;
parent->_bf = 0;
pSubL->_bf = 0;
}
(3)在较高右子树的左侧插入新结点——右左双旋
右左双旋分为三种情况分析,各种情况下的平衡因子的更新不同。
(1)pSubRL->bf = -1,更新pSubR->bf = 1;
(2) pSubRL不存在或者pSubRL->bf = 0时,不用更新pParent 和 pSubR;
(3) pSubRL->bf = 1时,更新pParent->bf = -1;
void RotateRL(PNode pParent)
{
PNode pSubR = pParent->_PRight;
PNode pSubRL = pSubR->_PLeft;
int bf = pSubRL->_bf;
RotateR(pParent->_PRight);
RotateL(pParent);
if (bf == -1)
pSubR->_bf = 1;
else if (bf == 1)
pParent->_bf = -1;
}
(4)在较高左子树的右侧插入新结点——左右双旋
左右双旋与右左双旋类似,也分为三种情况,在不同的情况下,对pParent 结点和 pSubL 结点的平衡因子的更新不同,类似于右左双旋,我们可以画图分析分析。
void RotateLR(PNode pParent)
{
PNode pSubL = pParent->_PLeft;
PNode pSubLR = pSubL->_PRight;
int bf = pSubLR->_bf;
RotateL(pParent->_PLeft);
RotateR(pParent);
if (bf == -1)
pParent->_bf = 1;
else if (bf == 1)
pSubL->_bf = -1;
}
再分析完四种旋转的情况后,我们来看下插入的整体代码
bool InsertNode(const K&key, const V& value)
{
if (_PRoot == NULL)
{
_PRoot = new Node(key, value);
return true;
}
PNode pcur = _PRoot;
PNode pParent = pcur->_pParent;
while (pcur)
{
if (pcur->_key > key)
{
pParent = pcur;
pcur = pcur->_PLeft;
}
else if (pcur->_key < key)
{
pParent = pcur;
pcur = pcur->_PRight;
}
else
return false;
}
pcur = new Node(key, value);
if (pParent->_key > key)
{
pParent->_PLeft = pcur;
pcur->_pParent = pParent;
}
else
{
pParent->_PRight = pcur;
pcur->_pParent = pParent;
}
while (pParent )
{
if (pParent->_PLeft == pcur)
pParent->_bf--;
else
pParent->_bf++;
if ( pParent->_bf == 0)
{
break;
}
else if (pParent->_bf == -1 || pParent->_bf == 1)
{
pcur = pParent;
pParent = pParent->_pParent;
}
else
{
//在较高右子树插入结点
if (pParent->_bf == 2)
{
PNode subR = pParent->_PRight;
if (subR->_bf == 1)//右子树的右侧,执行左单旋;
{
RotateL(pParent);
}
else if (subR->_bf == -1)//右子树的左侧,执行先右后左双旋
{
RotateRL(pParent);
}
}
else if (pParent->_bf == -2)
{
PNode subL = pParent->_PLeft;
if (subL->_bf == 1)//左子树的右侧,执行先左后右双旋
{
RotateLR(pParent);
}
else if (subL->_bf == -1)//左子树的左侧,执行右单旋
{
RotateR(pParent);
}
}
break;
}
}
return true;
}