AVL树的双旋转
- (D,F,G,C)代表四棵树,树高用h,h-1表示。
- 插入的方式有两种:
- 在E得左子树进行插入:需要先进行左旋转,在进行右旋转。
总结:
大于0进行左单旋,小于0进行右单选
平衡因子大于0(1),往左边树插入。
平衡因子小于0(-1),往右边的树插入
- 代码分析:如图所示
1.判断B结点的平衡因子大小。(右边高)
左边高 (右旋转)
右边高
- 判断结点E得平衡因子的大小。(平衡因子等于-1.说明做高右低,)
1.将ptr和leftsub的平衡因子分别置为1和0。
2.进行左单旋转和右单旋转。
void LeftBalance(AVLTree* ptree, AVLNode* ptr)
{
assert(ptree != nullptr && ptr != nullptr);
AVLNode* leftsub = ptr->leftchild, * rightsub = nullptr;
switch (leftsub->balance)
{
case 0: cout << "tree left balance " << endl;
break;
case -1: //左树高,右树低 ,一条斜线
ptr->balance = 0;
leftsub->balance = 0;
RotateRight(ptree, ptr); //进行右单旋
break;
case 1: //左低右高
rightsub = leftsub->rightchild;
switch (rightsub->balance) //得判断该结点得平衡因子,才知道插入的结点在
{ //左子树还是右子树
case 0:
ptr->balance = 0;
leftsub->balance = 0;
break;
case 1: //左低又高,一条斜线
ptr->balance = 0;
leftsub->balance = -1
break;
case -1:
ptr->balance = 1;
leftsub->balance = 0;
break;
}
rightsub->balance = 0;
RotateLeft(ptree, leftsub);
RotateRight(ptree, ptr);
break;
}
}
右子树
AVL树再平衡后,在插入新的节点后,不需要在进行回溯和调平。
原因:因为插入一个新的结点不会使树的高度加2,只会让树的高度加1.并且平衡因子最大为2,最小为-2.
并且当存在左子树或者右子树,插入新的结点到左子树或者右子树,当前插入节点的parent的高度不会发生变化。
- 和左平衡是镜像的
void RightBalance(AVLTree* ptree, AVLNode* ptr)
{
assert(ptree != nullptr && ptr != nullptr);
AVLNode* rightsub = ptr->rightchild, * leftsub = nullptr;
switch (rightsub->balance)
{
case 0: cout << "avl tree right balance " << endl; break;
case 1:
ptr->balance = 0;
rightsub->balance = 0;
RotateLeft(ptree, ptr);
break;
case -1:
leftsub = rightsub->leftchild;
switch (leftsub->balance)
{
case 0:
ptr->balance = 0;
rightsub->balance = 0;
break;
case 1:
ptr->balance = -1;
rightsub->balance = 0;
break;
case -1:
ptr->balance = 0;
rightsub->balance = 1;
break;
}
leftsub->balance = 0;
RotateRight(ptree, rightsub);
RotateLeft(ptree, ptr);
break;
}
}
void Adjust_Insert_Item(AVLTree* ptree, AVLNode* ptr)
{
assert(ptree != nullptr && ptr != nullptr);
bool taller = true; //树的高度,树的高度可能不变
AVLNode* pa = ptr->parent;
while (pa != nullptr && taller)
{
//左子树插入
if (pa->leftchild == ptr)
{
switch (pa->balance)
{
case 0: pa->balance = -1; break; //插入后parent为-1
case 1: pa->balance = 0; //parent为1,插入变为0
taller = false; //高度不变
break;
case -1: //插入后,需要调平
LeftBalance(ptree, pa);
taller = false;
break;
}
}
else //右子树插入
{ // ptr pa->rightchild
switch (pa->balance)
{
case 0: pa->balance = 1; break;
case -1: pa->balance = 0;
taller = false;
break;
case 1:
RightBalance(ptree, pa);
taller = false;
break;
}
}
ptr = pa;
pa = ptr->parent;
}
}
bool Insert_Item(AVLTree* ptree, const KeyType kx)
{
assert(ptree != nullptr);
AVLNode* ptr = ptree->root, * pa = nullptr;
while (ptr != nullptr && ptr->key != kx)
{
pa = ptr;
ptr = kx > ptr->key ? ptr->rightchild : ptr->leftchild;
}
if (ptr != nullptr && ptr->key == kx) return false;
ptr = Buynode();
ptr->key = kx;
ptr->parent = pa; //
if (pa != nullptr)
{
if (ptr->key > pa->key)
{
pa->rightchild = ptr;
}
else
{
pa->leftchild = ptr;
}
}
else
{
ptree->root = ptr;
}
Adjust_Insert_Item(ptree, ptr);//最后对整个树调平
ptree->cursize += 1;
}