MARK一篇关于AVL树的博客文章:数据结构图文解析之:AVL树详解及C++模板实现
一、AVL结构定义
struct AVLNode
{
int val;
struct AVLNode *left,*right;
int height;//AVL树的高度
};
typedef struct AVLNode AVLNode;
注:在节点中添加高度标记的原因在于,在每次进行计算高度时,可以不必要遍历访问到根节点,而仅仅向子树访问一次即可,从o(logn)变为o(1),这样可以提高效率。
注:高度改变的那些节点只可能是在第一次失衡节点向上到根中的路径上的节点。
二、几个函数
int Max(int a,int b){
return a>b?a:b;
}
int cptHeight(AVLNode *r){//计算树高
return r?r->height:-1;
}
三、AVL的旋转
AVLNode *lRotation(AVLNode *r)//左旋
{
AVLNode *p=r->right;
r->right=p->left;
p->left=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *rRotation(AVLNode *r)//右旋
{
AVLNode *p=r->left;
r->left=p->right;
p->right=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *lrRotation(AVLNode *r)//lr旋转
{
r->left=lRotation(r->left);
return rRotation(r);
}
AVLNode *rlRotation(AVLNode *r)//rl旋转
{
r->right=rRotation(r->right);
return lRotation(r);
}
四、AVL的插入
avl在每次插入之后,可能会导致失衡,在失衡节点处,每次进行旋转操作以保持其平衡性
AVLNode *AVLinsert(AVLNode *r,int e)
{
if(r==NULL){
r=(AVLNode*)malloc(sizeof(AVLNode));
r->val=e;
r->left=r->right=NULL;
r->height=0;//叶节点高度定义为0;
return r;
}
if(r->val<e){
r->right=AVLinsert(r->right,e);//在r右子树中插入节点
if(cptHeight(r->right)-cptHeight(r->left)>=2){//插入节点后可能引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//失衡节点r右子树的左右高度不可能相同
//r右子树左边高度大于右边,新插入节点在左边,应进行rl旋转,否则进行l旋转
}
}
else if(r->val>e){
r->left=AVLinsert(r->left,e);//在r左子树中插入节点
if(cptHeight(r->left)-cptHeight(r->right)>=2){//插入节点后可能引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//失衡节点r左子树的左右高度不可能相同
//左子树左边高度大于右边,新插入节点在左边,应进行r旋转,否则进行lr旋转
}
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
return r;
}
五、AVL的删除
删除节点时,与二叉搜索树一致,只是每次应该在删除的路径节点上,对相应失衡的节点进行旋转操作
AVLNode *AVLremove(AVLNode *r,int e)
{
if(r==NULL) return r;
if(r->val<e){
r->right=AVLremove(r->right,e);
}
else if(r->val>e){
r->left=AVLremove(r->left,e);
}
else{//找到当前需要删除的值
if(r->left&&r->right){//左右儿子都不为空
AVLNode *p=r->right;
while(p->left) p=p->left;//右边子树最小的值
r->val=p->val;
r->right=AVLremove(r->right,p->val);
}
else{
AVLNode *p=(r->left)?r->left:r->right;
free(r);
return p;
}
}
if(cptHeight(r->left)-cptHeight(r->right)>=2){//对右边节点进行删除引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//注意,此时失衡节点r左子树左右高度可能相等,相等时,采取不同的旋转策略将得到不同的AVL树
}else if(cptHeight(r->right)-cptHeight(r->left)>=2){//对左边节点进行删除引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//同上
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
//更新相应的节点高度值
return r;
}
六、完整测试代码
#include <stdio.h>
#include <malloc.h>
struct AVLNode
{
int val;
struct AVLNode *left,*right;
int height;//AVL树的高度
};
typedef struct AVLNode AVLNode;
int Max(int a,int b){
return a>b?a:b;
}
int cptHeight(AVLNode *r){
return r?r->height:-1;
}
AVLNode *lRotation(AVLNode *r)
{
AVLNode *p=r->right;
r->right=p->left;
p->left=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *rRotation(AVLNode *r)
{
AVLNode *p=r->left;
r->left=p->right;
p->right=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *lrRotation(AVLNode *r)
{
r->left=lRotation(r->left);
return rRotation(r);
}
AVLNode *rlRotation(AVLNode *r)
{
r->right=rRotation(r->right);
return lRotation(r);
}
AVLNode *AVLinsert(AVLNode *r,int e)
{
if(r==NULL){
r=(AVLNode*)malloc(sizeof(AVLNode));
r->val=e;
r->left=r->right=NULL;
r->height=0;//叶节点高度定义为0;
return r;
}
if(r->val<e){
r->right=AVLinsert(r->right,e);//在r右子树中插入节点
if(cptHeight(r->right)-cptHeight(r->left)>=2){//插入节点后可能引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//失衡节点r右子树的左右高度不可能相同
//r右子树左边高度大于右边,新插入节点在左边,应进行rl旋转,否则进行l旋转
}
}
else if(r->val>e){
r->left=AVLinsert(r->left,e);//在r左子树中插入节点
if(cptHeight(r->left)-cptHeight(r->right)>=2){//插入节点后可能引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//失衡节点r左子树的左右高度不可能相同
//左子树左边高度大于右边,新插入节点在左边,应进行r旋转,否则进行lr旋转
}
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
return r;
}
AVLNode *AVLremove(AVLNode *r,int e)
{
if(r==NULL) return r;
if(r->val<e){
r->right=AVLremove(r->right,e);
}
else if(r->val>e){
r->left=AVLremove(r->left,e);
}
else{//找到当前需要删除的值
if(r->left&&r->right){//左右儿子都不为空
AVLNode *p=r->right;
while(p->left) p=p->left;//右边子树最小的值
r->val=p->val;
r->right=AVLremove(r->right,p->val);
}
else{
AVLNode *p=(r->left)?r->left:r->right;
free(r);
return p;
}
}
if(cptHeight(r->left)-cptHeight(r->right)>=2){//对右边节点进行删除引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//注意,此时失衡节点r左子树左右高度可能相等,相等时,采取不同的旋转策略将得到不同的AVL树
}else if(cptHeight(r->right)-cptHeight(r->left)>=2){//对左边节点进行删除引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//同上
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
//更新相应的节点高度值
return r;
}
void pretra(AVLNode *r)//前序
{
if(r){
printf("<%d, %d> ",r->val,r->height);
pretra(r->left);
pretra(r->right);
}
}
void inotra(AVLNode *r)//中序
{
if(r){
inotra(r->left);
printf("<%d, %d> ",r->val,r->height);
inotra(r->right);
}
}
void tra(AVLNode *r){
printf("pretra: ");
pretra(r);
printf("\n");
printf("inotra: ");
inotra(r);
printf("\n");
}
int main()
{
char op;
int e;
AVLNode *r=NULL;
while(scanf("%c %d",&op,&e))
{
switch(op){
case 'i':r=AVLinsert(r,e),tra(r);break;//插入e
case 'r':r=AVLremove(r,e),tra(r);break;//删除e
default:printf("error\n");break;
}
getchar();
}
return 0;
}