版权声明:本文为博主原创文章,转载请附上博文链接! https://blog.csdn.net/weixin_40862011/article/details/84971724
ADT定义
左平衡处理
void LeftBalance(BBSTree &T) {
BBSTree lc, rd;
lc = T->lchild;
switch (lc->bf) {
case LH: //LL型,左高则右旋,右旋后均等高
T->bf = lc->bf = EH;
R_Rotate(T);
break;
case RH: //LR型,做双旋处理
rd = lc->rchild;
switch (rd->bf) { //修改T及其左孩子的平衡因子
case LH: {
T->bf = RH;
lc->bf = EH;
break;
} case EH: {
T->bf = lc->bf = EH;
break;
} case RH: {
T->bf = EH;
lc->bf = LH;
break;
}
}
rd->bf = EH;
L_Rotate(T->lchild); //对T的左子树作左旋调整
R_Rotate(T); //对T作右旋调整
break;
}
}
右平衡处理
void RightBalance(BBSTree &T) {
BBSTree rc, ld;
rc = T->rchild;
switch (rc->bf) {
case RH: //RR型,右高则左旋,左旋后等高
T->bf = rc->bf = EH;
L_Rotate(T);
break;
case LH: //RL型,做双旋处理
ld = rc->lchild;
switch (ld->bf) { //修改T及其右孩子的平衡因子
case RH:
T->bf = LH;
rc->bf = EH;
break;
case EH:
T->bf = rc->bf = EH;
break;
case LH:
T->bf = EH;
rc->bf = RH;
break;
}
ld->bf = EH;
R_Rotate(T->rchild); //对T的右子树作右旋调整
L_Rotate(T); //对T作左旋调整
break;
}
}
插入结点
- 若是空树,则插入结点作为根结点,树的高度增加1
- 若待插入结点和根结点相等,则插入失败
- 若待插入结点小于根结点,且在左子树中也不存在相等的结点,则在左子树插入,且若插入后的左子树高度增加1,分情况处理。
- 原根结点的平衡因子为-1,更改为0时,树的高度不变
- 原根结点的平衡因子为0时,更改为1,树的高度增加1
- 原根结点的平衡因子为1,若左子树根结点的平衡因子为1,则属于LL型,需进行右旋平衡调整,并在调整后将根结点及其右孩子的平衡因子更改为0时,树的高度不变;若左子树根结点的平衡因子为-1,则属于LR型,需依次进行左旋和右旋处理,并在调整后修改根结点以及其左右孩子的平衡因子,树的高度不变。
- 若待插入结点大于根结点,且在右子树中不存在相等的结点,则在右子树插入,且当插入后的右子树高度加1时,分情况处理。
- 原根结点的平衡因子为1,更改为0时,树的高度不变
- 原根结点的平衡因子为0时,更改为-1,树的高度增加1
- 原根结点的平衡因子为-1,若右子树根结点的平衡因子为-1,则属于RR型,需进行左旋平衡调整,并在调整后更新根结点及其左右子树根结点的平衡因子,树的高度不变;若右子树根结点的平衡因子为1,则属于RL型,需依次进行右旋和左旋处理,并在调整后修改根结点以及其左右孩子的平衡因子,树的高度不变。
Status InsertAVL(BBSTree &T, RcdType e, Status &taller) {
if (NULL == T) {
// T为空,树长高
T = (BBSTree)malloc(sizeof(BBSTNode));
T->data = e;
T->bf = EH;
T->lchild = NULL;
T->rchild = NULL;
taller = TRUE;
} else if (e.key == T->data.key) {
// 已经存在该点,插入失败
taller = FALSE;
return FALSE;
} else if (e.key < T->data.key) {
// 插入到左子树
if (FALSE == InsertAVL(T->lchild, e, taller)) {
return FALSE; //未插入
}
if (TRUE == taller) {
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 { //插入到右子树中
if (FALSE == InsertAVL(T->rchild, e, taller)) {
return FALSE;
}
if (TRUE == 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;
}
查找结点
BBSTree SearchBBST(BBSTree T, KeyType key) {
if (NULL == T)
return NULL;
if (T->data.key == key)
return T;
if (T->data.key > key)
return SearchBBST(T->lchild, key); //左子树递归查找
return SearchBBST(T->rchild, key); //右子树递归查找
}
凹入表打印
void ConcaveTablePrintBBST(BBSTree T,int level){
if(T == NULL) return;
int i ;
if(T->rchild)
ConcaveTablePrintBBST( T->rchild,level + 1);
for( i = 0;i < level; i++ )
printf(" "); //打印i个空格以表示出层次
printf("%d\n",T->data);
if(T->lchild)
ConcaveTablePrintBBST( T->lchild,level + 1);
}
求树深度
int TreeDepth(BBSTree T){
int rightdep,leftdep;
if(T == NULL)
return 0;
if(T->lchild != NULL)
leftdep = TreeDepth(T->lchild); //求左子树深度
else
leftdep = 0;
if(T->rchild != NULL)
rightdep = TreeDepth(T->rchild); //求右子树深度
else
rightdep = 0;
return (rightdep > leftdep) ? rightdep + 1 : leftdep + 1;
}
删除结点
首先在整个二叉树中搜索要删除的结点,如果没搜索到直接返回不作处理,否则执行以下操作:
- 要删除的结点是当前根结点Ť
如果左右子树都非空,在高度较大的子树中实施删除操作。
分两种情况:
1 )左子树高度大于右子树高度,将左子树中最大的那个元素赋给当前根结点,然后删除左子树中元素值最大的那个节点
2 )左子树高度小于右子树高度,将右子树中最小的那个元素赋给当前根结点,然后删除右子树中元素值最小的那个节点
如果左右子树都有一个为空,那么直接用那个非空子树或者是NULL替换当前根结点即可
2.要删除的结点元素值小于当前根结点Ť值,在左子树中进行删除
递归调用,在左子树中实施删除
这个是需要判断当前根结点是否仍然满足平衡条件
如果满足平衡条件,只需要更新当前根结点Ť的高度信息
否则需要进行旋转调整:
如果Ť的左子结点的左子树的高度大于Ť的左子结点的右子树的高度,进行相应的单旋转,否则进行双旋转。
3.要删除的结点元素值大于当前根结点Ť值,在右子树中进行删除
Status DeleteAVL(BBSTree &T, KeyType key, Status &shorter) {
if (NULL == T) {
// 树为空
return FALSE;
} else if (T->data.key == key) {
// 找到元素结点
BBSTree p = NULL;
if (NULL == T->lchild) {
// 左子树为空
p = T;
T = T->rchild;
free(p);
shorter = TRUE; // 高度变矮
} else if (T->rchild == NULL) {
// 右子树为空
p = T;
T = T->lchild;
free(p);
shorter = TRUE; // 高度变矮
} else {
// 左右子树都存在
p = T->lchild;
while (p->rchild != NULL) {
p = p->rchild;
}
T->data = p->data;
// 在左子树中删除前驱结点
DeleteAVL(T->lchild, p->data.key, shorter);
}
} else if (T->data.key > key) { //要删除的结点元素值小于当前根结点T值,在左子树中进行删除
if (DeleteAVL(T->lchild, key, shorter) == FALSE) {
return FALSE; //递归调用,在左子树中实施删除
}
if (shorter == TRUE) { //这个时候需要判断当前根结点是否仍然满足平衡条件
switch (T->bf) {
case LH: { //原左高,变等高,树变矮
T->bf = EH;
shorter = TRUE;
break;
} case EH: { //原等高,变右高
T->bf = RH;
shorter = FALSE;
break;
} case RH: {
RightBalance(T); //原右高,需进行右平衡处理
if (T->rchild->bf == EH) {
shorter = FALSE;
} else {
shorter = TRUE;
}
break;
}
}
}
} else { //要删除的结点元素值大于当前根结点T值,在右子树中进行删除
if (DeleteAVL(T->rchild, key, shorter) == FALSE) {
return FALSE; //递归调用,在右子树中实施删除
}
if (shorter == TRUE) {//这个时候需要判断当前根结点是否仍然满足平衡条件
switch (T->bf) {
case LH: { //原左高,需进行左平衡处理
LeftBalance(T);
if (T->lchild->bf == EH) {
shorter = FALSE;
} else {
shorter = TRUE;
}
break;
} case EH: { //原等高,变左高
T->bf = LH;
shorter = FALSE;
break;
} case RH: { //原右高,变等高,树变矮
T->bf = EH;
shorter = TRUE;
break;
}
}
}
}
return TRUE;
}
分裂
基本思想:将比基准关键字大的或者相等的结点插入到T2 树,小的插入到T1 树,新生成的两棵树都是平衡二叉树
void SpiltBBST(BBSTree T, KeyType key, BBSTree &T1, BBSTree &T2) {
Status taller = FALSE;
if (T != NULL) {
SpiltBBST(T->lchild, key, T1, T2); // 递归访问左子树
if(T->data.key > key) {
InsertAVL(T1, T->data, taller);
} else {
InsertAVL(T2, T->data, taller);
}
SpiltBBST(T->rchild, key, T1, T2); // 递归访问右子树
}
}
合并
void MergeBBST(BBSTree &T1, BBSTree T2) {
Status taller = FALSE;
if (T2 != NULL) {
MergeBBST(T1, T2->lchild); //每次往左子树遍历找到T的最小一个关键字
InsertAVL(T1, T2->data, taller); //调整为T1的根
MergeBBST(T1, T2->rchild);
}
}
相关源码看githubhttps://github.com/hxiaoxian/AVLTree