数据结构系列之平衡二叉树

1.基本介绍

平衡二叉树是一种特殊的二叉查找树,其左右子树都是平衡二叉树,且高度差的绝对值不超过1

如何使二叉查找树在添加数据的同时保持平衡呢?基本思想就是:当在二叉排序树中插入一个节点时,首先检查是否因插入而破坏了平衡,若破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达到新的平衡。所谓最小不平衡子树 指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。


插入操作下的四种平衡旋转情况:
1)绕某元素左旋转
对于一颗右子树高于左子树的平衡二叉树,当右子树的右子树插入了新的节点,平衡性被打破,则需要进行左旋,如下图

2)绕某元素右旋转
对于一颗左子树高于右子树的平衡二叉树,当左子树的左子树插入了新的节点,平衡被打破,则需要进行右旋,如下图
3)绕某元素的左子节点左旋转,再绕该元素进行右旋转
对于一颗左子树高于右子树的平衡二叉树,当左子树的右子树插入了新的节点,平衡被打破,需要先绕左子树的根节点进行左旋,再绕根节点进行右旋,如下图
4)绕某元素的右子节点右旋转,再绕该元素进行左旋转
对于一颗右子树高于左子树的平衡二叉树,当右子树的左子树插入了新的节点,平衡被打破,需要先绕右子树的根节点进行右旋,再绕根节点进行左旋,如下图

2.实现的C语言代码
#define LH 1
#define EH 0
#define RH -1

typedef struct TreeNode{
    int data;
    int bf;
    struct TreeNode* left=null;
    struct TreeNode* right=null;
}TreeNode,BiTree*;

//插入成功返回1,否则返回0
//树长高taller=1,否则taller=0
int InsertAVL(BiTree* T,int e,int* taller){
    if(!*T){
        *T=(BiTree)malloc(sizeof(TreeNode));
        (*T)->data=e;
        (*T)->bf=0;
        (*T)->left=(*T)->right=null;
    }else{
        if(e==(*T)->data){
            return 0;
        }
        
        if(e<(*T)->data){
            if(!InsertAVL(&(*T)->left,e,taller)){
                return 0;
            }
            
            if(taller){
                switch((*T)->bf){
					case LH:
						LeftBalance(T);
						*taller=0;
						break;
					case EH:
						(*T)->bf=LH;
						*taller=1;
						break;
					case RH:
						(*T)->bf=EH;
						*taller=0;
						break;
					}
            }
        }else{
            if(!InsertAVL(&(*T)->right,e,taller)){
                return 0;
            }
            
            if(taller){
                switch((*T)->bf){
					case LH:
						(*T)bf=EH;
						*taller=0;
						break;
					case EH:
						(*T)bf=RH;
						*taller=1;
						break;
					case RH:
						RightBalance(T);
						*taller=0;
						break;
					}
            }
        }
    }
    return 1;
}

void LeftBalance(BiTree* T){
        TreeNode L,Lr;
		L=(*T)->left;
		
		switch(L->bf){
		case LH:
			(*T)->bf=L->bf=EH;
			R_Rotate(T);
			break;
		case RH:
			Lr=L->right;
			switch(Lr->bf){
			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)->left);
			R_Rotate(T);
		}
}

void RightBalance(BiTree* T){
        TreeNode R,Rl;
		R=(*T)->right;
		
		switch(R->bf){
		case LH:
			Rl=R->left;
			switch(Rl->bf){
			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)->right);
			L_Rotate(T);
			break;
		case RH:
			(*T)->bf=R->bf=EH;
			L_Rotate(T);
		}
}

void L_Rotate(BiTree* T){
        BiTree R=(*T)->right;
		(*T)->right=R->left;
		R->right=(*T);
		(*T)=R;
}

void R_Rotate(BiTree* T){
        BiTree L=(*T)->left;
		(*T)->left=L->right;
		L->right=(*T);
		(*T)=L;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值