平衡二叉树的插入操作(AVL树)

一、AVL树的链式存储

typedef int ElementType; 
typedef struct AVLNode *Position;
typedef Position AVLTree;
struct AVLNode{
    ElementType Data;//结点数据 
    AVLTree Left;//指向左子树 
    AVLTree Right;//指向右子树 
    int Height;//树高 
}; 

二、旋转

  1. 左单旋

AVLTree SingleLeftRotation(AVLTree A)
{
    //A必须有一个左子节点B
    //返回新的根节点B
    printf("左单旋\n");
    AVLTree B=A->Left ;
    A->Left =B->Right ;
    B->Right=A;
    //更新树高 
    A->Height =Max(GetHeight(A->Left ),GetHeight(A->Right ))+1;
    B->Height =Max(GetHeight(B->Left ),A->Height )+1;
    
    return B;     
 } 
 
  1. 右单旋

AVLTree SingleRightRotation(AVLTree A)
{
    //A必须有一个右子节点B
    //返回新的根节点A
    printf("右单旋\n");
    AVLTree B=A->Right ;
    A->Right=B->Left ;
    B->Left =A;
    //更新树高
    A->Height =Max(GetHeight(A->Left ),GetHeight(A->Right ))+1;
    B->Height =Max(A->Height ,GetHeight(B->Right ))+1; 
 } 
  1. 左右双旋

AVLTree DoubleLeftRightRotation(AVLTree A)
{
    //A必须有一个左子节点B,B必须有一个右子节点C
    //返回新的根节点C
    
    printf("左右单旋\n");
    //将B与C做右单旋 ,返回C 
    A->Left =SingleRightRotation(A->Left );
    //将A与C做左单旋 ,返回C 
    return SingleLeftRotation(A);
 } 
  1. 右左双旋

AVLTree DoubleRightLeftRotation(AVLTree A)
{
    //A必须有一个右子节点B,B必须有一个左子节点C
    //返回新的根节点C
    
    printf("右左单旋\n");
    //将B与C做左单旋,返回C 
    A->Right=SingleLeftRotation(A->Right );
    //将A与C做右单旋 ,返回C 
    return SingleRightRotation(A);
}

三、插入

AVLTree Insert(AVLTree T,ElementType X)
{
    if(!T){
        //插入空树
         T=(AVLTree)malloc(sizeof(struct AVLNode));
         T->Data =X;
         T->Left =T->Right =NULL; 
         T->Height =1;
    }//树非空,选择插入左子树还是右子树 
    else if(X<T->Data ){//插入左子树 
        T->Left =Insert(T->Left ,X);
        //不平衡,需要左旋
        if(GetHeight(T->Left )-GetHeight(T->Right )==2)//不平衡的条件 
            if(X<T->Left->Data ) //在左边
                T=SingleLeftRotation(T);//左单旋 
            else //在右边 
                T=DoubleLeftRightRotation(T); //左右双旋
    }
    else if(X>T->Data ){//插入右子树 
        T->Right=Insert(T->Right ,X);
        //不平衡
        if(GetHeight(T->Right )-GetHeight(T->Left )==2)
            if(X>T->Right->Data )//在右边
                T=SingleRightRotation(T);//右单旋
            else //在左边
                T=DoubleRightLeftRotation(T);//右左双旋
    } 
    //else X==T->Data不需要插入
    
    //更新树高
    T->Height =Max(GetHeight(T->Left ),GetHeight(T->Right ))+1; //选择左右子树的最大高度并加上树根高度 
    
    return T;
}

四、完整代码

//平衡二叉树AVL


//AVL树的插入操作的非递归算法可读性差,使用通常使用递归算法来实现

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>


/*-------------AVL树的链式存储--------------------*/
typedef int ElementType; 
typedef struct AVLNode *Position;
typedef Position AVLTree;
struct AVLNode{
    ElementType Data;//结点数据 
    AVLTree Left;//指向左子树 
    AVLTree Right;//指向右子树 
    int Height;//树高 
}; 
/*-------------AVL树的链式存储结束--------------------*/

//树高
int GetHeight(AVLTree T)
{
    int LH,RH,MaxH;
    if(T){
        LH=GetHeight(T->Left );
        RH=GetHeight(T->Right );
        MaxH=LH>RH?LH:RH;
        return (MaxH+1);//返回树高 
    } 
    return 0;//空树高度为1 
 } 
 
//先序遍历
void PreorderTraversal(AVLTree T)
{
    if(T){
        printf("%d ",T->Data );
        PreorderTraversal(T->Left );
        PreorderTraversal(T->Right );
    }
 } 

//最大值 
int Max(int a,int b)
{
    //返回a,b中的较大值
    return a>b?a:b; 
}


/*-------------旋转--------------------*/
//左单旋
AVLTree SingleLeftRotation(AVLTree A)
{
    //A必须有一个左子节点B
    //返回新的根节点B
    printf("左单旋\n");
    AVLTree B=A->Left ;
    A->Left =B->Right ;
    B->Right=A;
    //更新树高 
    A->Height =Max(GetHeight(A->Left ),GetHeight(A->Right ))+1;
    B->Height =Max(GetHeight(B->Left ),A->Height )+1;
    
    return B;     
 } 
 
//右单旋
AVLTree SingleRightRotation(AVLTree A)
{
    //A必须有一个右子节点B
    //返回新的根节点A
    printf("右单旋\n");
    AVLTree B=A->Right ;
    A->Right=B->Left ;
    B->Left =A;
    //更新树高
    A->Height =Max(GetHeight(A->Left ),GetHeight(A->Right ))+1;
    B->Height =Max(A->Height ,GetHeight(B->Right ))+1; 
 } 
 
//左右双旋
AVLTree DoubleLeftRightRotation(AVLTree A)
{
    //A必须有一个左子节点B,B必须有一个右子节点C
    //返回新的根节点C
    
    printf("左右单旋\n");
    //将B与C做右单旋 ,返回C 
    A->Left =SingleRightRotation(A->Left );
    //将A与C做左单旋 ,返回C 
    return SingleLeftRotation(A);
 } 

//右左双旋 
AVLTree DoubleRightLeftRotation(AVLTree A)
{
    //A必须有一个右子节点B,B必须有一个左子节点C
    //返回新的根节点C
    
    printf("右左单旋\n");
    //将B与C做左单旋,返回C 
    A->Right=SingleLeftRotation(A->Right );
    //将A与C做右单旋 ,返回C 
    return SingleRightRotation(A);
}

/*-------------旋转结束--------------------*/

/*-------------插入函数--------------------*/
AVLTree Insert(AVLTree T,ElementType X)
{
    if(!T){
        //插入空树
         T=(AVLTree)malloc(sizeof(struct AVLNode));
         T->Data =X;
         T->Left =T->Right =NULL; 
         T->Height =1;
    }//树非空,选择插入左子树还是右子树 
    else if(X<T->Data ){//插入左子树 
        T->Left =Insert(T->Left ,X);
        //不平衡,需要左旋
        if(GetHeight(T->Left )-GetHeight(T->Right )==2)//不平衡的条件 
            if(X<T->Left->Data ) //在左边
                T=SingleLeftRotation(T);//左单旋 
            else //在右边 
                T=DoubleLeftRightRotation(T); //左右双旋
    }
    else if(X>T->Data ){//插入右子树 
        T->Right=Insert(T->Right ,X);
        //不平衡
        if(GetHeight(T->Right )-GetHeight(T->Left )==2)
            if(X>T->Right->Data )//在右边
                T=SingleRightRotation(T);//右单旋
            else //在左边
                T=DoubleRightLeftRotation(T);//右左双旋
    } 
    //else X==T->Data不需要插入
    
    //更新树高
    T->Height =Max(GetHeight(T->Left ),GetHeight(T->Right ))+1; //选择左右子树的最大高度并加上树根高度 
    
    return T;
}
/*-------------插入结束--------------------*/

//输出
void PrintResult(AVLTree T)
{
    int h=GetHeight(T);
    printf("树高为:%d\n",h); 
    printf("先序遍历:");
    PreorderTraversal(T);
    printf("\n");
}
 
int main()
{
    AVLTree T=NULL,Head=NULL;;
    ElementType X;
    
    printf("请输入根节点:");
    scanf("%d",&X);
    T=Insert(T,X);
    Head=T;
    
    int i;
    printf("请输入5个子节点:"); 
    for(i=0;i<5;i++){
        scanf("%d",&X);
        T=Insert(T,X);
    }
    
    PrintResult(T);
    
    return 0;
}

运行:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值