右旋操作
//对以p为根的二叉排序树作右旋处理
//处理之后p指向新的树根结点,即旋转处理之前的左子树的根节点
void R_Rotate(BiTree &p){
BiTree L;
L=p->lchild;//L指向p的左子树的根节点
p->lchild=L->rchild;//L的右子树挂接为p的左子树
L->rchild=p;
p=L;//p指向新的根节点
}
左旋操作
/*对以p为根的二叉排序树作左旋处理
处理之后p指向新的树根结点,即旋转处理之前的右子树的根节点
*/
void L_Rotate(BiTree &p){
BiTree R;
R=p->rchild;//R指向P的右子树的根节点
p->rchild=R->lchild;//R的左子树挂接为p的右子树
R->lchild=p;
p=R;//p指向新的根节点
}
左平衡旋转处理
/*对以指针T所指结点为根的二叉树作左平衡旋转处理
本算法结束时,指针T指向新的根节点*/
void LeftBalance(BiTree &T){
BiTree L,Lr;
L=T->lchild;//L指向T的左子树根节点
switch(L->bf){
//检查T的左子树的平衡度,并作相应平衡处理
case LH://新结点插入在T的左孩子的左子树上,要作单右旋处理
T->bf=L->bf=EH;
R_Rotate(T);
break;
case RH://新结点插入在T的左孩子的右子树上,要作双旋处理
Lr=L->rchild;//Lr指向T的左孩子的右子树根
switch(Lr->bf)//修改T及其左孩子的平衡因子
{
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->lchild);//对T的左子树作左旋平衡处理
R_Rotate(T);//对T作右旋平衡处理
}
}
右平衡旋转处理
void RightBalance(BiTree &T){
BiTree R,Rl;
R=T->rchild;
switch(R->bf){
case RH://对应于RR
T->bf=R->bf=EH;
L_Rotate(T);
break;
case LH://对应于RL
Rl=R->lchild;
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->rchild);
L_Rotate(T);
}
}
平衡二叉树的插入
/*
若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个
数据元素为e的新结点,并返回true;否则返回false;若因插入而使二叉
排序树失去平衡,则要做平衡旋转处理,布尔变量taller反映T长高与否
*/
bool InsertAVL(BiTree &T, int e,bool &taller){
if(!T){
//插入新结点,树长高,置taller=true;
T=(BiTree)malloc(sizeof(BiTNode));
T->data=e;
T->lchild=T->rchild=NULL;
T->bf=EH;
taller=true;
}
else{
if(e == T->data){
//树中已存在和e有相同关键字的结点而不再插入
taller=false;
return false;
}
if(e < T->data){
//应继续在T的左子树中进行搜索
if(!InsertAVL(T->lchild, e, taller))//未插入
return false;
if(taller){
//已插入到T的左子树中且左子树长高
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{
//应继续在T的右子树中进行搜索
if(!InsertAVL(T->rchild, e, taller))//未插入
return false;
if(taller){
//检查T的平衡度
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;
}
完整测试代码
//平衡二叉树,简称平衡树AVL树,G.M.Adelson-Velsky和E.M.Landis
#include<stdio.h>
#include<stdlib.h>
#define ElemType int
#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
//平衡二叉树结点
typedef struct BiTNode{//结点结构
ElemType data;//结点数据
int bf;//结点的平衡因子
struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
//对以p为根的二叉排序树作右旋处理
//处理之后p指向新的树根结点,即旋转处理之前的左子树的根节点
void R_Rotate(BiTree &p){
BiTree L;
L=p->lchild;//L指向p的左子树的根节点
p->lchild=L->rchild;//L的右子树挂接为p的左子树
L->rchild=p;
p=L;//p指向新的根节点
}
/*对以p为根的二叉排序树作左旋处理
处理之后p指向新的树根结点,即旋转处理之前的右子树的根节点
*/
void L_Rotate(BiTree &p){
BiTree R;
R=p->rchild;//R指向P的右子树的根节点
p->rchild=R->lchild;//R的左子树挂接为p的右子树
R->lchild=p;
p=R;//p指向新的根节点
}
/*对以指针T所指结点为根的二叉树作左平衡旋转处理
本算法结束时,指针T指向新的根节点*/
void LeftBalance(BiTree &T){
BiTree L,Lr;
L=T->lchild;//L指向T的左子树根节点
switch(L->bf){
//检查T的左子树的平衡度,并作相应平衡处理
case LH://新结点插入在T的左孩子的左子树上,要作单右旋处理
T->bf=L->bf=EH;
R_Rotate(T);
break;
case RH://新结点插入在T的左孩子的右子树上,要作双旋处理
Lr=L->rchild;//Lr指向T的左孩子的右子树根
switch(Lr->bf)//修改T及其左孩子的平衡因子
{
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->lchild);//对T的左子树作左旋平衡处理
R_Rotate(T);//对T作右旋平衡处理
}
}
void RightBalance(BiTree &T){
BiTree R,Rl;
R=T->rchild;
switch(R->bf){
case RH://对应于RR
T->bf=R->bf=EH;
L_Rotate(T);
break;
case LH://对应于RL
Rl=R->lchild;
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->rchild);
L_Rotate(T);
}
}
/*
若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个
数据元素为e的新结点,并返回true;否则返回false;若因插入而使二叉
排序树失去平衡,则要做平衡旋转处理,布尔变量taller反映T长高与否
*/
bool InsertAVL(BiTree &T, int e,bool &taller){
if(!T){
//插入新结点,树长高,置taller=true;
T=(BiTree)malloc(sizeof(BiTNode));
T->data=e;
T->lchild=T->rchild=NULL;
T->bf=EH;
taller=true;
}
else{
if(e == T->data){
//树中已存在和e有相同关键字的结点而不再插入
taller=false;
return false;
}
if(e < T->data){
//应继续在T的左子树中进行搜索
if(!InsertAVL(T->lchild, e, taller))//未插入
return false;
if(taller){
//已插入到T的左子树中且左子树长高
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{
//应继续在T的右子树中进行搜索
if(!InsertAVL(T->rchild, e, taller))//未插入
return false;
if(taller){
//检查T的平衡度
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;
}
void visit(BiTree T){
printf("%d ",T->data);
}
//二叉树的中序遍历
void InOrder(BiTree T){
if(T){
InOrder(T->lchild);//递归遍历左子树
visit(T);
InOrder(T->rchild);
}
}
void PreOrder(BiTree T){
if(T){
visit(T);
PreOrder(T->lchild);//递归遍历左子树
PreOrder(T->rchild);
}
}
//后序遍历,销毁二叉排序树
bool DestroyBiTree(BiTree T){//删除不用&
if(T==NULL){
printf("空节点#\n");
return false;
}
DestroyBiTree(T->lchild);
DestroyBiTree(T->rchild);
printf("销毁%d\n",T->data);
free(T);
T=NULL;//防止产生野指针
return true;
}
int main(){
int i;
int a[10]={3,2,1,4,5,6,7,10,9,8};
BiTree T=NULL;
bool taller;
for(i=0;i<10;i++){
InsertAVL(T,a[i],taller);
}
printf("中序遍历:\n");
InOrder(T);
printf("\n\n可以根据前序和中序遍历的输出结果来画出平衡二叉树\n进而验证结果的正确性\n");
printf("\n\n前序遍历:\n");
PreOrder(T);
printf("\n\n用完记得销毁哦(按后序遍历依次销毁)!\n");
DestroyBiTree(T);
return 0;
}