平衡二叉树的基本操作

版权声明:本文为博主原创文章,转载请附上博文链接! 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
  2. 若待插入结点和根结点相等,则插入失败
  3. 若待插入结点小于根结点,且在左子树中也不存在相等的结点,则在左子树插入,且若插入后的左子树高度增加1,分情况处理。
    • 原根结点的平衡因子为-1,更改为0时,树的高度不变
    • 原根结点的平衡因子为0时,更改为1,树的高度增加1
    • 原根结点的平衡因子为1,若左子树根结点的平衡因子为1,则属于LL型,需进行右旋平衡调整,并在调整后将根结点及其右孩子的平衡因子更改为0时,树的高度不变;若左子树根结点的平衡因子为-1,则属于LR型,需依次进行左旋和右旋处理,并在调整后修改根结点以及其左右孩子的平衡因子,树的高度不变。
  4. 若待插入结点大于根结点,且在右子树中不存在相等的结点,则在右子树插入,且当插入后的右子树高度加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. 要删除的结点是当前根结点Ť

         如果左右子树都非空,在高度较大的子树中实施删除操作。

        分两种情况:

         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

猜你喜欢

转载自blog.csdn.net/weixin_40862011/article/details/84971724