AVL树

平衡二叉树:是一种二叉排序树,树中的每一个结点都满足,其左子树的深度与右子树深度的差值的最对值小于1.
平衡因子(Balanec factor):结点的左子树深度与右子树深度的差值,显然平衡二叉树中每个结点的平衡因子的值只能为-1,0 , 1.
最小不平衡子树:距离插入结点最近的,且平衡因子大于1的子树的根结点。
AVL树的建立:其实是按照二叉排序树的规则对树逐个插入结点,由于结点插入后,各结点的平衡因子会发生变化,可从底往上通过判断当前结点BF的值,来找到最小不平衡树,然后做出对应的操作,使之满足AVL树。

左旋与右旋操作示意图
左旋
这里写图片描述

新的结点的插入会导致原AVL的平衡被打破,共有两大类:(1)外部插入:最小不平衡树根结点与孩子结点的bf的符号相同(左左,右右),(2)内部插入:最小不平衡树的根结点与孩子结点的bf符号不相同(左右,右左)。对于情况(1),只需要但旋转后便能恢复平衡,而情况(2)则需要双旋转才能恢复平衡。
以下给出最小不平衡子树类型示意图:
这里写图片描述
这里写图片描述

代码

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

#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
#define SUCCESS 1
#define FAIL 0


typedef int status;

typedef struct avltnode//定义AVL树结点结构体,及结点指针类型
{
    int data;
    struct avltnode *lchild,*rchild;
    int bf;
}avltnode,* avlptr;

void L_Rotate(avlptr *T)//左旋操作
{
    avlptr r;
    r = (*T)->rchild;//指向右孩子结点
    (*T)->rchild = r->lchild;//右孩子结点的左子树挂接为原根结点的右子树
    r->lchild = (*T);//指向新的根结点
    *T = r;//指向新的根结点
}

void R_Rotate(avlptr *T)//右旋操作
{
    avlptr l;
    l = (*T)->lchild;//指向左孩子结点
    (*T)->lchild = l->rchild;//左孩子结点的右子树挂接为原根结点的左子树
    l->rchild = (*T);
    *T = l;//指向新的根结点
}
/*在根结点的左子树插入时,当且仅当在左孩子结点的左子树插入时,根结点的bf和左孩子结点的bf是符号相同的
  这样的最小不平衡树共三种情况,可通过右旋后恢复平衡,且都满足(*T)->bf = l->bf =EH;
  而在左孩子的右子树插入时,根结点的bf和左孩子结点的bf符号时不相同的,因此需要先左旋左孩子使得符号相同
  再通过右旋恢复平衡,对应的最小不平衡子树也有三种情况
同理可得右子树中的插入情况*/
void leftbalance(avlptr *T)//调整左子树的平衡因子及对应的连接关系
{
    avlptr l,lr;
    l = (*T)->lchild;
    switch (l->bf)
    {
        case LH://外部插入  左左 左右
            (*T)->bf = l->bf =EH;
            R_Rotate(T);
            break;
        case RH://内部插入   右左 右右
            lr = l->rchild;
            switch(lr->bf)
            {
                case EH://lr为叶子结点
                    (*T)->bf = l->bf = EH;
                    break;
                case LH://
                    lr->bf = EH;
                    (*T)->bf = RH;
                    l->bf = EH;
                    break;
                case RH:
                    l->bf =LH;
                    lr->bf =EH;
                    (*T)->bf = EH;
                    break;
            }
            L_Rotate(&(*T)->lchild);//左旋左孩子结点
            R_Rotate(T);//右旋操作
    }
}

void rightbalance(avlptr *T)
{
    avlptr r,rl;
    r = (*T)->rchild;
    switch (r->bf)
    {
       case RH:
           (*T)->bf = r->bf = EH;
           L_Rotate(T);
           break;
       case LH:
           rl = r->lchild;
           switch (rl->bf)
           {
               case EH:
                   (*T)->bf = r->bf = EH;//插入点的bf没有变化
                   break;
               case LH:
                   (*T)->bf =EH;
                   rl->bf =EH;
                   r->bf = RH;
                   break;
               case RH:
                   rl->bf = EH;
                   (*T)->bf =LH;
                   break;
           }
           R_Rotate(&(*T)->rchild);//右旋操作
           L_Rotate(T);//左旋

    }
}

status InsertAvltnode(avlptr *T,int e,int * taller)//平衡二叉排序树插入结点
{
    avlptr l,r;
    //*T 为根结点地址、e为需要插入的元素、*taller为布尔变量,用于判断子树是否长高了
    if((*T)==NULL)//找到对应的位置进行插入
    {
        *T = (avlptr)malloc(sizeof(avltnode));
        (*T)->data = e;
        (*T)->lchild = NULL;
        (*T)->rchild = NULL;
        (*T)->bf = 0;
        *taller = 1;//增高了
        return SUCCESS;//插入成功
    }
    else
    {
        if (e==(*T)->data)//AVL树中含有这个值,不插入
        {
            *taller = 0;
            return FAIL;
        }
        else if(e<(*T)->data)
        {
            if(InsertAvltnode(&(*T)->lchild,e,taller)==0)//继续遍历左子树,进行查找
            {
                return FAIL;//没有插入,返回
            }
            if((*taller)==1)//左子树中插入成功
            {
                switch ((*T)->bf)//从该叶子结点网上
                {
                    case EH:
                        (*T)->bf = LH;
                        *taller = 1;
                        break;
                    case LH://
                        leftbalance(T);//平衡左子树
                        *taller = 0;
                        break;
                    case RH:
                        (*T)->bf = EH;
                        *taller = 0;
                        break;

                }
            }
        }
        else if(e>(*T)->data)
        {
            if(InsertAvltnode(&(*T)->rchild,e,taller)==0)//继续遍历右子树,进行查找
            {
                return FAIL;//没有插入,返回
            }
            if((*taller)==1)//右子树中插入成功
            {
                switch ((*T)->bf)//从该叶子结点往上找到最小不平衡子树
                {
                    case EH:
                        (*T)->bf = RH;
                        *taller = 1;
                        break;
                    case LH://
                        (*T)->bf = EH;
                        *taller = 0;
                        break;
                    case RH:
                        rightbalance(T);//平衡左子树
                        *taller = 0;

                        break;

                }
            }
        }
        return SUCCESS;
    }
}
void InorderTranverse(avlptr T)//中序遍历二叉树
{
    if (T==NULL)
    {
        return;
    }
    else
    {
        InorderTranverse(T->lchild);
        printf("%d\n",T->data);
        InorderTranverse(T->rchild);
    }
}
status Avl_Search(avlptr T,int e,avlptr * add,int *count)//avl树查找
{
    (*count)++;
    if (T==NULL)//没有找到
    {
        return FAIL;
    }
    else 
    {
        if(e==T->data)
        {
           *add = T;//返回对应地址
           return SUCCESS;
        }
        else if(e<T->data)
        {
            Avl_Search(T->lchild,e,add,count);
        }
        else 
            Avl_Search(T->rchild,e,add,count);
    }
}
void main()
{
    avlptr AvlT =NULL;
    int taller =0;
    //int a[]={1,2,3,4,5,6,7,8,9,10};
    int a[]={6,2,1,3,4,10,7,8,5,9};
    int i;//循环记录
    int count[10]={0};//记录查找对应a[i]所用的次数
    avlptr add = NULL;
    //建立avl树
    for (i=0;i<10;i++)
    {
        InsertAvltnode(&AvlT,a[i],&taller);
    }
    InorderTranverse(AvlT);

    for (i=0;i<10;i++)
    {
        if(Avl_Search(AvlT,a[i],&add,&count[i]))//avl树查找
        {
        printf("%p,%3d,%3d\n",add,a[i],count[i]);
        }
    }

    getchar();
}

运行结果:
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值