平衡二叉排序树
平衡二叉排序树是在插入函数中处理
/* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */
/* 数据元素为e的新结点并返回1,否则返回0.若因插入而使二叉排序树 */
/* 失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否 */
Status InsertAVL(BiTree* T, int e, Status *taller)
{
if (!*T)
{/* 插入新结点,树"长高",置taller为TRUE */
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = e;
(*T)->lchild = (*T)->rchild = NULL;
(*T)->bf = EH;
*taller = TRUE;
}
else
{
if (e == (*T)->data)
{ /* 树中已存在和e有相同关键字的结点则不再插入 */
*taller = FALSE;
return FALSE;
}
if (e < (*T)->data)
{/* 应继续在T的左子树中进行搜索 */
if (!InsertAVL(&(*T)->lchild, e, taller)) /* 未插入 */
return FALSE;
if (*taller) /* 已插入到T的左子树中且左子树"长高" */
{
switch ((*T)->bf) /* 检查T的平衡度 */
{
case LH: /* 原本左子树比右子树高,需要作左平衡处理 */
LeftBalance(T);
*taller = FALSE;
break;
case EH: /* 原本左右子树等高,现在因左子树增高而树增高 */
(*T)->bf = LH;
*taller = TRUE;
break;
case RH:/* 原本右子树比左子树高,现在左、右子树等高 */
(*T)->bf = EH;
*taller = FALSE;
break;
}
}
}
else
{/* 应继续在T的右子树中进行搜索 */
if (!InsertAVL(&(*T)->rchild, e, taller)) /* 未插入 */
return FALSE;
if (*taller) /* 已插入到T的左子树中且左子树"长高" */
{
switch ((*T)->bf) /* 检查T的平衡度 */
{
case LH: /* 原本左子树比右子树高,现在左、右子树等高 */
(*T)->bf = EH;
*taller = FALSE;
break;
case EH: /* 原本左右子树等高,现在因右子树增高而树增高 */
(*T)->bf = LH;
*taller = TRUE;
break;
case RH:/* 原本右子树比左子树高,需要作右平衡(左旋转)处理 */
RightBalance(T);
*taller = FALSE;
break;
}
}
}
}
return TRUE;
}
当传入的T的第一层为NULL,即为整颗树为空时,对该结点进行插入操作,并修改taller变量为TRUE,最后该函数结束返回一个TRUE;表示插入成功
或者当传入的T的第一层为不为NULL,即为整颗树不为空时,
则有三种情况:
1、当要插入的结点的data值e等于T的data值时;
taller值为FALSE,返回一个FALSE值,表示插入失败。
2、当要插入的结点的data值e小于T的data值时;
递归调用该函数,并传入T的左子树,e,taller;
当递归的返回值为FALSE时;
即插入失败,此时需要继续返回FASLE,表示插入失败,直到递归结束。
或者当递归的返回值为TRUE时,即插入成功时;
继续往下执行,第一次执行时,是插入结点的上一级;因为当插入成功后taller值为TRUE,即树增高,需要做相应处理;
此时分三种情况:
第一,当当前结点的bf值为1,即原本左子树比右子树高,又因为插入结点插入在当前结点的左子树,此时需要做左平衡处理,调用左平衡处理函数并将taller值修改为FALSE,因为左平衡处理后树就平衡了,即不需要再处理了,所以taller为FALSE。
第二,当当前结点的bf值为0,即原本左子树和右子树等高,又因为插入结点插入在当前结点的左子树,此时需要将T的bf值修改为1,因为插入结点后因左子树增高而树增高;taller值为TRUE,即上一层还需要继续处理。
第三,当当前结点的bf值为-1,即原本右子树比左子树高,又因为插入结点插入在当前结点的左子树,此时需要将T的bf值修改为0,因为插入结点后因左右子树登高;taller值为FALSE,即其它层不需要处理;因为只是在原本的基础上再加一个左子树,所以对其它层没有影响。
3、当要插入的结点的data值e大于T的data值时;
递归调用该函数,并传入T的左子树,e,taller;
当递归的返回值为FALSE时;
即插入失败,此时需要继续返回FASLE,表示插入失败,直到递归结束。
或者当递归的返回值为TRUE时,即插入成功时;
继续往下执行,第一次执行时,是插入结点的上一级;因为当插入成功后taller值为TRUE,即树增高,需要做相应处理;
此时分三种情况:
第一,当当前结点的bf值为1,即原本左子树比右子树高,又因为插入结点插入在当前结点的右子树,此时需要将T的bf值修改为0,因为插入结点后因左右子树登高;taller值为FALSE,即其它层不需要处理;因为只是在原本的基础上再加一个右子树,所以对其它层没有影响。
第二,当当前结点的bf值为0,即原本左子树和右子树等高,又因为插入结点插入在当前结点的右子树,此时需要将T的bf值修改为-1,因为插入结点后因右子树增高而树增高;taller值为TRUE,即上一层还需要继续处理。
第三,当当前结点的bf值为-1,即原本右子树比左子树高,又因为插入结点插入在当前结点的右子树,此时需要做右平衡处理,调用右平衡处理函数并将taller值修改为FALSE,因为右平衡处理后树就平衡了,即不需要再处理了,所以taller为FALSE。
左平衡函数:
/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/
/*本算法结束时,指针T指向新的根节点*/
void LeftBalance(BiTree* T)
{
BiTree L, Lr;
L = (*T)->lchild; /*L指向T的左子树根节点*/
switch (L->bf)
{/* 检查T的左子树的平衡度,并作相应平衡处理 */
case LH: /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */
(*T)->bf = L->bf = EH;
R_Rotate(T);
break;
case RH: /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */
Lr = L->rchild; /* Lr指向T的左孩子的右子树根 */
switch (Lr->bf) /* 修改T及其左孩子的平衡因子 */
{
case LH:
(*T)->bf = RH;
L->bf = EH;
break;
case EH:
(*T)->bf = L->bf = EH;
break;
case RH:
(*T)->bf = EH;
L->bf = LH;
break;
}
Lr->bf = EH;
L_Rotate(&(*T)->lchild);/* 对T的左子树作左旋平衡处理 */
R_Rotate(T); /* 对T作右旋平衡处理 */
break;
}
}
当需要左平衡的时候,该T的bf值为1;
L为T的左子树,因为需要做左平衡处理时,该树的层序至少为3;
L的bf值不可能为0;即L的左右子树的深度差为1;
当L的bf值为1时,即新插入结点在L的左子树上或为L的左子树;
此时满足右旋转的条件;直接将T和L的bf值都修改为0,再调用右旋转函数将T作为参数传入。
当L的bf值为-1时,即插入结点在L的右子树上或为L的右子树;
此时不满足右旋转条件,需要将L进行左旋转再将T右旋转且将Lr的bf值修改为0,因为Lr最后会成为根节点,T指向Lr;并将T和L的bf值进行相应的修改。
Lr为L的右子树,
当Lr的bf值为1时,说明新插入结点为Lr的左子树,
此时需要将T的bf值改为-1,L的bf值为0;
在双旋转后,因为是左平衡,所以新插入结点N的data值<T的data值;又因为N为Lr的左子树,所以N的data值<Lr的data值;即N<T且N<Lr;所以T的左子树为空值,所以T的bf值为-1
因为Lr为L的右子树,Lr的所有结点都比L大,所以N的data值>L的data值,又因为N为Lr的左子树,所以N的data值<Lr的data值,即L<N<Lr,所以L的右子树为新结点N,所以L的bf值为0;
当Lr的bf值为0时,说明新插入结点为L的右子树,即Lr为新结点,Lr的左右子树为空;
在双旋转后,因为Lr不存在左右结点,所以T和L的bf值都为0;
当Lr的bf值为-1时,说明新插入结点为Lr的右子树,
此时需要将T的bf值改为0,L的bf值为1;
在双旋转后,因为是左平衡,所以新插入结点N的data值<T的data值;又因为N为Lr的右子树,所以N的data值>Lr的data值;即Lr<N<T;所以T的左子树为新结点N,所以T的bf值为0
因为Lr为L的右子树,Lr的所有结点都比L大,所以N的data值>L的data值,又因为N为Lr的右子树,所以N的data值>Lr的data值,即L<N且Lr<N,所以L的右子树为空,所以L的bf值为1;
右平衡函数:
/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/
/*本算法结束时,指针T指向新的根节点*/
void RightBalance(BiTree* T)
{
BiTree R, Rl;
R = (*T)->rchild; /*L指向T的右子树根节点*/
switch (R->bf)
{/* 检查T的右子树的平衡度,并作相应平衡处理 */
case LH: /* 新结点插入在T的右孩子的左子树上,要作双旋处理 */
Rl = R->lchild; /* Lr指向T的右孩子的左子树根 */
switch (Rl->bf) /* 修改T及其右孩子的平衡因子 */
{
case LH:
(*T)->bf = EH;
R->bf = RH;
break;
case EH:
(*T)->bf = R->bf = EH;
break;
case RH:
(*T)->bf = LH;
R->bf = EH;
break;
}
Rl->bf = EH;
R_Rotate(&(*T)->rchild);/* 对T的右子树作右旋平衡处理 */
L_Rotate(T); /* 对T作左旋平衡处理 */
break;
case RH: /* 新结点插入在T的右孩子的右子树上,要作单左旋处理 */
(*T)->bf = R->bf = EH;
L_Rotate(T);
break;
}
}
当需要右平衡的时候,该T的bf值为-1;
R为T的右子树,因为需要做右平衡处理时,该树的层序至少为3;
R的bf值不可能为0;即R的左右子树的深度差为1;
当R的bf值为1时,即新插入结点在R的左子树上或为R的左子树;
此时不满足左旋转条件,需要将R进行右旋转再将T左旋转且将Rl的bf值修改为0,因为Rl最后会成为根节点,T指向Rl;并将T和R的bf值进行相应的修改。
Rl为R的左子树,
当Rl的bf值为1时,说明新插入结点为Rl的左子树,
此时需要将T的bf值改为0,R的bf值为-1;
在双旋转后,因为是右平衡,所以新插入结点N的data值>T的data值;又因为N为Rl的左子树,所以N的data值<Rl的data值;即T<N<Rl;所以T的右子树为新结点N,所以T的bf值为0
因为Rl为R的左子树,Rl的所有结点都比L小,所以N的data值<R的data值,又因为N为Rl的左子树,所以N的data值<Lr的data值,即N<Rl且N<R,所以R的左子树为空,所以R的bf值为-1;
当Rl的bf值为0时,说明新插入结点为R的左子树,即Rl为新结点,Rl的左右子树为空;
在双旋转后,因为Rl不存在左右结点,所以T和R的bf值都为0;
当Rl的bf值为-1时,说明新插入结点为Rl的右子树,
此时需要将T的bf值改为1,L的bf值为0;
在双旋转后,因为是右平衡,所以新插入结点N的data值>T的data值;又因为N为Rl的右子树,所以N的data值>Rl的data值;即Rl<N且T<N;所以T的右子树为空,所以T的bf值为1
因为Rl为R的左子树,Rl的所有结点都比R小,所以N的data值<R的data值,又因为N为Rl的右子树,所以N的data值>Rl的data值,即Rl<N<R,所以R的左子树为新结点N,所以R的bf值为0;
当R的bf值为-1时,即插入结点在R的右子树上或为R的右子树;
此时满足左旋转的条件;直接将T和R的bf值都修改为0,再调用左旋转函数将T作为参数传入。
左旋转函数:
void L_Rotate(BiTree *p)
{
BiTree R;
R = (*p)->rchild; /*L指向p的右子树根结点*/
(*p)->rchild = R->lchild;/*将p的右子树指向 p的左子树的右子树*/
R->lchild = (*p);/*p的右子树的右子树指向P*/
(*p) = R; /*p指向R*/
}
将T的左子树L的右子树置为T的左子树,将T置为L的右子树,T指向L,表示L为根结点;
若L的右子树不存在则T不存在左子树;直接将T置为L的右子树;
右旋转函数:
void R_Rotate(BiTree *p)
{
BiTree L;
L = (*p)->lchild; /*L指向p的左子树根节点*/
(*p)->lchild = L->rchild;/*将p的左子树指向 p的左子树的右子树*/
L->rchild = (*p);/*p的左子树的右子树指向P*/
(*p) = L; /*p指向L*/
}
将T的右子树R的左子树置为T的右子树,将T置为R的左子树,T指向R,表示R为根结点;
若R的左子树不存在则T不存在右子树;直接将T置为R的左子树;
在插入时,左平衡调用的是单右旋转,或者是双旋,左旋转后右旋转;
右平衡是单左旋转,或者是双旋。又旋后左旋``