平衡二叉树的定义:
为避免树的高度增长过快,降低二叉排序树的性能,规定在插入和删除二叉树结点时,要保证任意结点的左、右子树高度差的绝对值不超过1,将这样的二义树称为平衡二叉树AVL (Balanced Binary Tree),简称平衡树。
平衡二叉树的插入:
(1) LL平衡旋转(右单旋)
由于在结点A的左孩子(L的在子树(L上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树大去平衡,需要一次向右的旋转操作。将A的左孩子B向右上旋转代替A成为根结点,将A结点向右下旋转成为B的右子树的根结点,而B的原右子树则作为A结点的左子树。
如图7.11所示,结点旁的数值代表结点的平衡因子,而用方块表示相应结点的子树,下方数值代表该子树的高度。
(2) RR平衡旋转(左单旋转)
由于在结点A的右孩子(R)的右子树(R)上插入了新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。将A的右孩子B向左上旋转代替A成为根结点,将A结点向左下旋转成为B的左子树的根结点,而B的原左子树则作为A结点的右子树.
(3) LR平衡旋转(先左后右旋转)
由于在A 的左孩子(L)的右子树(R)上插入新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转。先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后把该C结点向右上旋转提升到A结点的位置.
(4)RL平衡旋转(先右后左双旋转)
由于在A的右孩子(R)的左子树(L)上插入新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转。先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置,然后把该C结点向左上旋转提升到A结点的位置.
1.定义结构体
typedef struct TreeNode
{
int data;//定义数据域
int height;//定义高度
struct TreeNode *lchild;//左孩子
struct TreeNode *rchild;//右孩子
}TreeNode;
2.获取结点高度
int getHeight(TreeNode *node)
{
return node ? node->height : 0;//判断node是否为空,为空返回0,不为空返回高度
}
3.取最大值
int max(int a,int b)
{
return a > b ? a : b;
}
4.RR平衡旋转(向左旋转一次)
void rrRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
TreeNode *temp = node->rchild;//右孩子保存给中间指针
node->rchild = temp->lchild;//node的左孩子赋值给node的右孩子
temp->lchild = node;//node代替node的左孩子
node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;//最大值加一
temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
*root = temp;
}
5.LL平衡旋转(向右旋转一次)
void llRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
TreeNode *temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;
temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
*root = temp;
}
6.建立平衡二叉树
void avlInsert(TreeNode **T,int data)
{/*第一个参数**T:双重解引用,用于更改T中的值
第二个参数data:用于传递元素并比较大小*/
if(*T==NULL)//首先判断该结点是否为空,是空结点则新建结点并初始化
{
*T = (TreeNode*)malloc(sizeof(TreeNode));//申请内存空间
(*T)->data = data;//写入数据
(*T)->height = 0;//高度初始化为0
(*T)->lchild = NULL;//左孩子初始为空
(*T)->rchild = NULL;//右孩子初始为空
}
else if(data<(*T)->data)//data小于当前结点值
{
avlInsert(&(*T)->lchild,data);//要插入的元素比结点内的元素小,则往左子树走
//拿到当前左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
if(lHeight-rHeight==2)//判断二叉树是否失衡
{//判断高度差
if(data<(*T)->lchild->data)//要插入的元素小于当前结点左孩子的元素
{//LL型
llRotation(*T,T);//右旋一次
}
else
{//LR型
rrRotation((*T)->lchild,&(*T)->lchild);//先左旋
llRotation(*T,T);//后右旋
}
}
}
else if(data>(*T)->data)//data大于当前结点值
{
avlInsert(&((*T)->rchild),data);//要插入的元素比结点内的元素大,则往右子树走
//拿到当前左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
if(rHeight-lHeight==2)//判断二叉树是否失衡
{//判断高度差
if (data>(*T)->rchild->data)
{//RR型
rrRotation(*T,T);//左旋一次
}
else
{//RL型
llRotation((*T)->rchild,&(*T)->rchild);//先右旋
rrRotation(*T,T);//后左旋
}
}
}
(*T)->height = max(getHeight((*T)->lchild),getHeight((*T)->rchild))+1;
}
7.前序遍历(根左右)
void preOrder(TreeNode *T)
{
if(T)
{
printf("%d ",T->data);//输出根结点
preOrder(T->lchild);//递归遍历左子树
preOrder(T->rchild);//递归遍历右子树
}
}
8.主函数
int main()
{
TreeNode *T = NULL;//初始树根结点
int nums[5] = {1,2,3,4,5};
int i;
for(i=0;i<5;i++)
avlInsert(&T,nums[i]);//构造平衡二叉树
preOrder(T);
printf("\n");
return 0;
}
完整代码:
#include <stdio.h>
#include <stdlib.h>
/*定义结构体*/
typedef struct TreeNode
{
int data;//定义数据域
int height;//定义高度
struct TreeNode *lchild;//左孩子
struct TreeNode *rchild;//右孩子
}TreeNode;
/*获取结点高度*/
int getHeight(TreeNode *node)
{
return node ? node->height : 0;//判断node是否为空,为空返回0,不为空返回高度
}
/*取最大值*/
int max(int a,int b)
{
return a > b ? a : b;
}
/*RR平衡旋转(向左旋转一次)*/
void rrRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
TreeNode *temp = node->rchild;//右孩子保存给中间指针
node->rchild = temp->lchild;//node的左孩子赋值给node的右孩子
temp->lchild = node;//node代替node的左孩子
node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;//最大值加一
temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
*root = temp;
}
/*LL平衡旋转(向右旋转一次)*/
void llRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
TreeNode *temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;
temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
*root = temp;
}
/*建立平衡二叉树*/
void avlInsert(TreeNode **T,int data)
{/*第一个参数**T:双重解引用,用于更改T中的值
第二个参数data:用于传递元素并比较大小*/
if(*T==NULL)//首先判断该结点是否为空,是空结点则新建结点并初始化
{
*T = (TreeNode*)malloc(sizeof(TreeNode));//申请内存空间
(*T)->data = data;//写入数据
(*T)->height = 0;//高度初始化为0
(*T)->lchild = NULL;//左孩子初始为空
(*T)->rchild = NULL;//右孩子初始为空
}
else if(data<(*T)->data)//data小于当前结点值
{
avlInsert(&(*T)->lchild,data);//要插入的元素比结点内的元素小,则往左子树走
//拿到当前左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
if(lHeight-rHeight==2)//判断二叉树是否失衡
{//判断高度差
if(data<(*T)->lchild->data)//要插入的元素小于当前结点左孩子的元素
{//LL型
llRotation(*T,T);//右旋一次
}
else
{//LR型
rrRotation((*T)->lchild,&(*T)->lchild);//先左旋
llRotation(*T,T);//后右旋
}
}
}
else if(data>(*T)->data)//data大于当前结点值
{
avlInsert(&((*T)->rchild),data);//要插入的元素比结点内的元素大,则往右子树走
//拿到当前左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
if(rHeight-lHeight==2)//判断二叉树是否失衡
{//判断高度差
if (data>(*T)->rchild->data)
{//RR型
rrRotation(*T,T);//左旋一次
}
else
{//RL型
llRotation((*T)->rchild,&(*T)->rchild);//先右旋
rrRotation(*T,T);//后左旋
}
}
}
(*T)->height = max(getHeight((*T)->lchild),getHeight((*T)->rchild))+1;
}
/*前序遍历(根左右)*/
void preOrder(TreeNode *T)
{
if(T)
{
printf("%d ",T->data);//输出根结点
preOrder(T->lchild);//递归遍历左子树
preOrder(T->rchild);//递归遍历右子树
}
}
int main()
{
TreeNode *T = NULL;//初始树根结点
int nums[5] = {1,2,3,4,5};
int i;
for(i=0;i<5;i++)
avlInsert(&T,nums[i]);//构造平衡二叉树
preOrder(T);
printf("\n");
return 0;
}
运行结果: