原理:每当构建一个二叉树时,先检查插入是否破坏了平衡性。若是,则找出最小不平衡子树,进行对应的操作。
//树结构定义
typedef struct BiTnode {
int data;
int bf;
struct BiTnode* lchild, * rchild;
}BiTnode, *BiTree;
左旋即将最小不平衡子树的根节点变为其右孩子的左子树。原右孩子的左子树变为原根节点的右子树。
//左旋操作
void L_Rotate(BiTree* P) {
BiTree R;
R = (*P)->rchild;
(*P)->rchild = R->lchild;
R->lchild = (*P);
*P = R;
}
右旋即将最小平衡子树的根节点变为其左孩子的右子树。原左孩子的右子树变为原根节点的左子树。
//右旋操作
void R_Rotate(BiTree* P) {
BiTree L;
L = (*P)->lchild;
(*P)->lchild = L->rchild;
L->rchild = (*P);
*P = L;
}
左平衡操作:对于较复杂情况,例如:即最小子树的根节点的平衡因子bf 为+2但其左孩子的平衡因子为-1。此时我们需要先将左孩子调整为与根节点同号即先对左孩子的右子树进行左旋,再对原根节点的子树进行右旋。同时要修改对应情况下新的平衡因子。
#define LH +1
#define EH 0
#define RH -1
void LeftBalance(BiTree* T) {
// L为T的左孩子,Lr为L的右孩子
BiTree L, Lr;
L = (*T)->lchild;
//L的平衡因子bf为+1导致T不平衡时
//调整平衡因子
//右旋即可
if (L->bf == LH) {
(*T)->bf = L->bf = EH;
R_Rotate(T);
}
//L的bf为-1时需要分情况讨论
else if (L->bf == RH) {
Lr = L->rchild;
//L的右孩子也为-1时,在经过调整后T的平衡因子最终为0
//L的bf最终为+1
if (Lr->bf == RH) {
(*T)->bf = EH;
L->bf = LH;
}
//同理,建议自己推一下调整后的情况
else if (Lr->bf == EH) {
(*T)->bf = L->bf = EH;
}
else if (Lr->bf == LH) {
(*T)->bf = RH;
L->bf = EH;
}
Lr->bf = EH;
L_Rotate(&(*T)->lchild);
R_Rotate(T);
}
}
右平衡操作同理。
AVL的插入操作:
bool InsertAVL(BiTree* T, int e, bool* taller) {
if (! *T) {
*T = (BiTree)malloc(sizeof(BiTnode));
(*T)->data = e;
(*T)->lchild = (*T)->rchild = nullptr;
(*T)->bf = EH;
*taller = true;
}
else {
//若插入数值已有
if (e == (*T)->data) {
*taller = false;
return false;
}
if (e < (*T)->data) {
//若插入数值小于根节点的数值,在左子树寻找
//若最终插入不成功
if (!InsertAVL(&(*T)->lchild, e, taller))
return false;
//若树最终增高
if (*taller) {
switch ((*T)->bf) {
//若插入前左边高
case LH:
LeftBalance(T);
//调整后树未增高
taller = false;
break;
//插入前为相等
//树增高
case EH:
(*T)->bf = LH;
*taller = true;
break;
//插入前右边高
//插入完两边相等
//树未增高
case RH:
(*T)->bf = EH;
*taller = false;
break;
}
}
}
else {
if (!InsertAVL(&(*T)->rchild, e, taller))
return false;
if (*taller) {
switch ((*T)->bf) {
case LH:
(*T)->bf = EH;
taller = false;
break;
case EH:
(*T)->bf = RH;
*taller = true;
break;
case RH:
RightBalance(T);
*taller = false;
break;
}
}
}
}
return true;
}