【数据结构】平衡二叉树的概念及其实现

什么是平衡二叉树?

对于二叉搜索树,节点的不同插入次序,将导致不同的深度和查找效率。这样就出现了一个问题。如何设计二叉树的结构可以让查找效率更高呢?如果一棵树它的左右子树都一样。既左右子树的高度和节点的数量都一样这样的树,查找效率就最高可是这个都一样的要求太高了。我们把标准再降低一点就有了平衡二叉树。
平衡因子:BF(T)=HL- HR;其中HL,HR分别代表数T的左右子树的高度。
平衡二叉树(AVL树):空树,或者左子树和右子树的高度差的绝对值不超过1,既| BF(T) |<=1.。
平衡二叉树的调整:
平衡二叉树在插入或删除一个节点后,可能会让二叉树失去平衡。根据不同的实际情况,

我们将二叉树的调整分为如下几种方法:

RR旋转:
实际情况:
在这里插入图片描述
如图所示左边的树插入节点C后,A节点的平衡因子变为-2.这时我们称不平衡的“发现者”是A节点,平衡的破坏者,既麻烦节点是C节点,它在“发现者”节点A的右孩子的右子树上。这种情况我们采用RR旋转得到右边的树。(RR旋转又称右单旋)
所有麻烦节点在发现者右孩子的右子树既需要(RR旋转)的情况可以概括为下图:
在这里插入图片描述
LL旋转:
在这里插入图片描述
如图所示:左树插入节点A后破坏了C节点的平衡。麻烦节点A,在发现者节点C的左孩子的左子树上
这种情况我们用LL旋转得到右边的树。(LL旋转又称左单旋)
所有麻烦节点在发现者的左孩子的左子树上既需要(LL旋转)的情况可以概括为下图:
在这里插入图片描述
LR旋转:
在这里插入图片描述
如图所示:左树插入节点C后破坏了E节点的平衡。麻烦节点C,在发现者节点E的左孩子的右子树上
这种情况我们用LR旋转得到右边的树。(LR旋转又称LR双旋,因为就上图而言;他是先以发现者节点E的左孩子B为根节点,做一次右单旋,再以E为根节点做一次左单旋形成的)
所有麻烦节点在发现者的左孩子的右子树上既需要(LR旋转)的情况可以概括为下图:
在这里插入图片描述
RL旋转:
在这里插入图片描述
如图所示:左树插入节点D后破坏了B节点的平衡。麻烦节点D,在发现者节点B的右孩子的左子树上
这种情况我们用RL旋转得到右边的树。(RL旋转又称 RL双旋,原因与LR双选类似)
所有麻烦节点在发现者的左孩子的右子树上既需要(RL旋转)的情况可以概括为下图:
在这里插入图片描述

平衡二叉树调整的实现:

#include<stdio.h>
#include<stdlib.h>
#define Elementype char
typedef struct AVLTree{//AVL树的结构
	Elementype data;
	struct AVLTree* L_child;
	struct AVLTree* R_child;
	int Hight;//树的高度
}AVLTree;
int Max ( int a, int b )
{
    return a > b ? a : b;
}
int GetHight(AVLTree* A){//获取树的高度
	if(!A){
		return -1;
	}else{
		return A ->Hight;
	}
}
AVLTree* SingleLeftRotation ( AVLTree* A ){//LL旋转(左单旋)
	// 注意:A必须有一个左子结
	// 将A与B做左单旋,更新A与B的高度,返回新的根结点B     
	
	AVLTree* B = A ->L_child;
	A ->L_child = B ->R_child;
	B ->R_child = A;
	A ->Hight = Max(GetHight(A ->L_child) ,GetHight(A ->R_child)) + 1;
	B ->Hight = A ->Hight + 1;
	return B;
}
AVLTree* SinglRightRotation ( AVLTree* A ){//RR旋转(右单旋)
	// 注意:A必须有一个右孩子
	// 将A与B做右单旋,更新A与B的高度,返回新的根结点B     
	
	AVLTree* B = A ->R_child;
	A ->R_child = B ->L_child;
	B ->L_child = A;
	A ->Hight = Max(GetHight(A ->L_child) ,GetHight(A ->R_child)) + 1;
	B ->Hight = A ->Hight + 1;
	return B;
}
AVLTree* LeftRightRotation ( AVLTree* A ){//LR旋转 (先以A -> L_child 做一次RR旋转,再以A为根节点做一次LL旋转)
	// 注意:A必须有一个左孩子(B),B必须有一个右孩子(C)
	
	AVLTree* B = A ->L_child;
	A ->L_child = SinglRightRotation(B);
	return SingleLeftRotation(A);
}
AVLTree* RightLeftRotation ( AVLTree* A ){//RL旋转(先以A ->R_child 做一次LL旋转,再以A为根节点做一次RR旋转)
	// 注意:A必须有一个右孩子(B),B必须有一个左孩子(C)
	
	AVLTree* B = A ->R_child;
	A ->R_child = SingleLeftRotation(B);
	return SinglRightRotation(A);
}
AVLTree* Insert(  AVLTree* A , Elementype data ){//平衡树的插入操作
	if(!A){
		A = (AVLTree*)malloc(sizeof(AVLTree));
		A ->data = data;
		A ->Hight = 0;
		A ->L_child = A ->R_child = NULL;
	}else if(data < A ->data){//data 应插入A的左子树
		A ->L_child = Insert( A ->L_child , data);
		if(GetHight( A ->L_child ) - GetHight( A ->R_child) == 2){//插入后不平衡
			if(data < A ->L_child ->data){//LL旋转
				A = SingleLeftRotation(A);
			}else{//LR旋转
				A = LeftRightRotation(A);
			}
		}
	}else if(data > A ->data){// data应插入A的右子树
		A ->R_child = Insert(A ->R_child , data);
		if( GetHight( A ->L_child ) - GetHight( A ->R_child ) == -2 ){
			if( data > A ->R_child ->data ){//RR旋转
				A = SinglRightRotation(A);
			}else{//RL旋转
				A = RightLeftRotation(A);
			}
		}
	}
	//更新树的高度
	A ->Hight = Max( GetHight( A ->L_child) , GetHight( A ->R_child )) + 1;
	return A;
}
void Pre_show_Tree(AVLTree* ptr){//先序遍历输出AVL树
	if(ptr){
		printf("%c ",ptr ->data);
		Pre_show_Tree(ptr ->L_child);
		Pre_show_Tree(ptr ->R_child);
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值