一.平衡二差树的概念
平衡二叉树的定义:对于平衡二叉树中的每个节点其左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)。在这里我们为了讲解方便把平衡因子定为:右树最大高度减去左树最大高度。
节点的定义如下:
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf; // balance factor
pair<K, V> _kv;
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
, _kv(kv)
{}
};
二.插入步骤
步骤如下:
1.插入:先按照二叉搜索树的规则将节点插入到AVL树中
2.更新父节点的平衡因子:新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1,如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1。
3.根据父节点的平衡因子判定:
a.如果Parent的平衡因子为0,说明插入之前Parent的平衡因子为正负1,插入后被调整成0,此时插入没有改变高度,满足,不用做任何处理。
b.如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,改变了树的高度,以pParent为根的树的高度增加,需要将pParent看成新插入的节点,重新从步骤二开始。如下图所示:需要将parent看成新插入的节点,跳转到步骤2,更新grandfather节点的平衡因子。
c.如果Parent的平衡因子为正负2,则Parent的平衡因子违反平衡树的性质,需要对其进行旋转处理。就如上图所示,此时已经不是平衡二叉树,需要进行处理。
该步骤用代码表示如下:
bool Insert(const pair<K, V>& kv)
//1.找到插入位置并插入
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
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)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent)
{
//2.更新平衡因子
if (cur == parent->_left)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
//3.根据平衡因子判断
//bf=0,不用处理跳出循环
if (parent->_bf == 0)
{
break;
}
//bf=1或-1,需要更新节点
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = cur->_parent;
parent = parent->_parent;
}
//bf=2或-2,需要选择选转
else if (parent->_bf == 2 || parent->_bf == -2)
{
//选转操作
}
else
{
assert(false)//插入前就出错了
}
return true;
}
三.旋转操作
我们首先要明白刚插入节点时,只看父子节点那俩层并不会出现旋转的情况,在我们不断向上更新时才会根据不同情况来决定要不要旋转。更新节点后要进行的旋转主要分为四种类型。
第一二种情况是单旋,后俩种是双旋。
代码如下:
else if (parent->_bf == 2 || parent->_bf == -2)
{
if (parent->_bf == 2 && cur->_bf == 1)
{
/* p
h c
h h
o*/
leftrevolve(parent);
break;
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
/* p
c h
h h
o */
rightrevolve(parent);
break;
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
Node* rightch = parent->_right;
Node* rlch = rightch->_left;
int rl_bf = rlch->_bf;
rlrevolve(parent);
/* p
h c
h h
o */
if (rl_bf == 1)
{
parent->_bf = -1;
rightch->_bf = 0;
rlch->_bf = 0;
}
/* p
h c
h h
o */
else if (rl_bf == -1)
{
parent->_bf = 0;
rightch->_bf = 1;
rlch->_bf = 0;
}
/* p
c
o */
else if (rl_bf == 0)
{
parent->_bf = 0;
rightch->_bf = 0;
rlch->_bf = 0;
}
else
{
assert(false);
}
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
/* p
c h
h h
o */
Node* leftch = parent->_left;
Node* lrch = leftch->_right;
lr_bf = lrch->_bf;
lrrevolve(parent);
if (lr_bf == 1)
{
leftch->_bf = -1;
parent->_bf = 0;
lrch->_bf = 0;
}
else if (lr_bf == -1)
{
parent->_bf = 1;
leftch->_bf = 0;
lrch->_bf = 0;
}
else if (lr_bf == 0)
{
parent->_bf = 0;
leftch->_bf = 0;
lrch->_bf = 0;
}
}
else
{
assert(false);
}
}
void leftrevolve(Node* parent)
{
Node* rightch = parent->_right;
Node* pp = parent->_parent;
Node* rlch = parent->_right->_left;
parent->_right= rlch;
rightch->_left=parent;
parent->_parent = rightch;
rightch->_parent = pp;
if (rlch)
{
rlch->_parent = parent;
}
if (pp == nullptr)
{
_root = rightch;
}
else
{
if (pp->_right == parent)
{
pp->_right = rightch;
}
else if (pp->_left == parent)
{
pp->_left =rightch;
}
}
parent->_bf = 0;
rightch->_bf = 0;
return;
}
void rightrevolve(Node* parent)
{
Node* leftch = parent->_left;
Node* pp = parent->_parent;
Node* lrch = parent->_left->_right;
leftch->_right=parent;
parent->_left = lrch;
parent->_parent = leftch;
leftch->_parent = pp;
if (lrch)
{
lrch->_parent = parent;
}
if (pp == nullptr)
{
_root = leftch;
}
else
{
if (pp->_right == parent)
{
pp->_right = leftch;
}
else if (pp->_left == parent)
{
pp->_left =leftch;
}
}
parent->_bf = 0;
leftch->_bf = 0;
return;
}
void rlrevolve(Node* parent)
{
rightrevolve(parent->_right);
leftrevolve(parent);
}
void lrrevolve(Node* parent)
{
leftrevolve(parent->_left);
rightrevolve(parent);
}