平衡二叉树 AVL

笔记:
1、 在包含有n个结点的平衡树上查找的时间复杂度为 O(log n),深度也和O(log n)同数量级。
在平衡树上进行查找的过程和排序树相同,因此,在查找过程中和给定值进行比较的关键字个数不超过树的深度。
2、 二叉排序树又称为二叉查找树。
3、 平衡二叉树必须是二叉查找树。
4、 AVL树的查找、插入、删除操作在平均和最坏的情况下都是O(logn),这得益于它时刻维护着二叉树的平衡。如果我们需要查找的集合本身没有顺序,在频繁查找的同时也经常的插入和删除,AVL树是不错的选择。不平衡的二叉查找树在查找时的效率是很低的,因此,AVL如何维护二叉树的平衡是我们的学习重点。
**注意:**对于平衡因子的计算建议通过记录树的高度来计算比较方便,单纯的记录平衡因子会很麻烦。
推荐两个比较好的网址:
http://www.cnblogs.com/QG-whz/p/5167238.html
http://blog.csdn.net/whucyl/article/details/17289841
实现代码:

#include <iostream>
#include <stdio.h>
#include <malloc.h>
#include <math.h>
typedef int ATElemType;
using namespace std;

typedef struct ATNode
{
    ATElemType key;
    int height;
    struct ATNode *lChild;
    struct ATNode *rChild;
}ATNode, *AVLtree;
///Get height
int GetHeight(AVLtree root)
{
    if(root==NULL)
        return 0;
    else
        return root->height;
}
///Update height
void updateHeight(AVLtree &root)
{
    if(root!=NULL)
        root->height=max(GetHeight(root->lChild),GetHeight(root->rChild))+1;
}
///LL型,右旋
void rRotate(AVLtree &root)
{
    ATNode *p=root->lChild;
    root->lChild=p->rChild;
    p->rChild=root;
    updateHeight(root);
    updateHeight(p);
    root=p;
}
///RR型,左旋
void lRotate(AVLtree &root)
{
    ATNode *p=root->rChild;
    root->rChild=p->lChild;
    p->lChild=root;
    updateHeight(root);
    updateHeight(p);
    root=p;
}
///LR型,左旋再右旋
void LRrotate(AVLtree &root)
{
    lRotate(root->lChild);
    rRotate(root);
}
///RL型,右旋再左旋
void RLrotate(AVLtree &root)
{
    rRotate(root->rChild);
    lRotate(root);
}
///插入节点--递归
AVLtree insertElem_AVL(AVLtree &root,ATElemType eKey)
{
    if(root!=NULL)
    {
        if(root->key==eKey)
        {
            return root;
        }
        else if(root->key>eKey)  //插在左子树上
        {
            root->lChild=insertElem_AVL(root->lChild,eKey);
            updateHeight(root);
            if(GetHeight(root->lChild)-GetHeight(root->rChild)==2)
            {
                if(GetHeight(root->lChild->lChild)>GetHeight(root->lChild->rChild))  //LL
                    rRotate(root);
                else  //LR
                    LRrotate(root);
            }
        }
        else //root->key<eKey  //插在右子树上
        {
            root->rChild=insertElem_AVL(root->rChild,eKey);
            updateHeight(root);
            if(GetHeight(root->lChild)-GetHeight(root->rChild)==-2)
            {
                if(GetHeight(root->rChild->rChild)>GetHeight(root->rChild->lChild))//RR
                    lRotate(root);
                else  //RL
                    RLrotate(root);
            }
        }
        return root;
    }
    else
    {
        root=(AVLtree)malloc(sizeof(ATNode));
        root->key=eKey;
        root->height=1;
        root->lChild=root->rChild=NULL;
        return root;
    }
}
///求一棵树中的最大值点
AVLtree maxValue_AVL(AVLtree root)
{
    if(root!=NULL)
    {
        ATNode *p;
        for(p=root;p->rChild!=NULL;p=p->rChild){}
        return p;
    }
}
///求一棵树中的最小值点
AVLtree minValue_AVL(AVLtree root)
{
    if(root!=NULL)
    {
        ATNode *p;
        for(p=root;p->lChild!=NULL;p=p->lChild){}
        return p;
    }
}
///删除指定的元素
AVLtree DeleteElem_AVL(AVLtree &root,ATElemType eKey)
{
    if(root!=NULL)
    {
        if(root->key==eKey)
        {
            if(root->lChild==NULL&&root->rChild==NULL)
            {
                free(root);
                root=NULL;
                return root;
            }
            else if(root->lChild==NULL)
            {
                ATNode *p=root;
                root=root->rChild;
                free(p);
                p=NULL;
                return root;
            }
            else if(root->rChild==NULL)
            {
                ATNode *p=root;
                root=root->lChild;
                free(p);
                p=NULL;
                return root;
            }
            else  //左右子树均不为空
            {
                if(GetHeight(root->lChild)>=GetHeight(root->rChild))  //左子树高
                {
                    root->key=maxValue_AVL(root->lChild)->key;
                    root->lChild=DeleteElem_AVL(root->lChild,root->key);
                    updateHeight(root);
                    if(GetHeight(root->rChild)-GetHeight(root->lChild)==2)//在左子树上删除结点相当于在右子树上插入节点
                    {
                        if(GetHeight(root->rChild->rChild)>GetHeight(root->rChild->lChild))
                            lRotate(root);
                        else
                            RLrotate(root);
                    }
                }
                else  //右子树高
                {
                    root->key=minValue_AVL(root->rChild)->key;
                    root->rChild=DeleteElem_AVL(root->rChild,root->key);
                    updateHeight(root);
                    if(GetHeight(root->lChild)-GetHeight(root->rChild)==2)//在右子树上删除结点相当于在左子树上插入节点
                    {
                        if(GetHeight(root->lChild->lChild)>GetHeight(root->lChild->rChild))
                            rRotate(root);
                        else
                            LRrotate(root);
                    }
                }
                return root;
            }
        }
        else if(root->key>eKey) //在左子树上
        {
            root->lChild=DeleteElem_AVL(root->lChild,eKey);
            updateHeight(root);
            if(GetHeight(root->rChild)-GetHeight(root->lChild)==2)//在左子树上删除结点相当于在右子树上插入节点
            {
                if(GetHeight(root->rChild->rChild)>GetHeight(root->rChild->lChild))
                    lRotate(root);
                else
                    RLrotate(root);
            }
            return root;
        }
        else  //在右子树上
        {
            root->rChild=DeleteElem_AVL(root->rChild,eKey);
            updateHeight(root);
            if(GetHeight(root->lChild)-GetHeight(root->rChild)==2)//在右子树上删除结点相当于在左子树上插入节点
            {
                if(GetHeight(root->lChild->lChild)>GetHeight(root->lChild->rChild))
                    rRotate(root);
                else
                    LRrotate(root);
            }
            return root;
        }
    }
    else
        return NULL;
}
///中序遍历
void Inorder_AVL(AVLtree root)
{
    if(root)
    {
        Inorder_AVL(root->lChild);
        printf("%d ",root->key);
        Inorder_AVL(root->rChild);
    }
}
///前序遍历
void PreOrder_AVL(AVLtree root)
{
    if(root)
    {
        printf("%d ",root->key);
        PreOrder_AVL(root->lChild);
        PreOrder_AVL(root->rChild);
    }
}
///后序遍历
void PostOrder_AVL(AVLtree root)
{
    if(root)
    {
        PostOrder_AVL(root->lChild);
        PostOrder_AVL(root->rChild);
        printf("%d ",root->key);
    }
}
///查找元素---递归
AVLtree searchElem_AVL(AVLtree root,ATElemType eKey)
{
    if(root)
    {
        if(root->key==eKey)
            return root;
        else if(root->key>eKey)
            searchElem_AVL(root->lChild,eKey);
        else
            searchElem_AVL(root->rChild,eKey);
    }
    else
        return NULL;
}
///查找元素---非递归
AVLtree searElemNoRecurse_AVL(AVLtree root,ATElemType eKey)
{
    ATNode *p=root;
    while(p)
    {
        if(p->key==eKey)
            return p;
        else if(p->key>eKey)
            p=p->lChild;
        else
            p=p->rChild;
    }
    return NULL;
}
///销毁AVL
void Destroy_AVL(AVLtree &root)
{
    if(root)
    {
        Destroy_AVL(root->lChild);
        Destroy_AVL(root->rChild);
        free(root);
        root=NULL;
    }
}

int main()
{
    AVLtree mAVL=NULL;
    //---test insert---
    insertElem_AVL(mAVL,5);
    insertElem_AVL(mAVL,8);
    insertElem_AVL(mAVL,7);
    insertElem_AVL(mAVL,2);
    insertElem_AVL(mAVL,3);
    insertElem_AVL(mAVL,4);
    insertElem_AVL(mAVL,6);
    insertElem_AVL(mAVL,9);
    int height=GetHeight(mAVL);
    printf("%d\n",height);
    Inorder_AVL(mAVL);
    printf("\n");
    //--test delete---
//    DeleteElem_AVL(mAVL,5);
//    height=GetHeight(mAVL);
//    printf("%d\n",height);
//    Inorder_AVL(mAVL);
//    printf("\n");
//    printf("%d\n",mAVL->key);
    //---test preOrder---
//    PreOrder_AVL(mAVL);
//    printf("\n");
    //---test postOrder---
//    PostOrder_AVL(mAVL);
//    printf("\n");
    //---test search(递归)---
//    printf("%d\n",searchElem_AVL(mAVL,8)->key);
    //---test search(非递归)---
//    printf("%d\n",searElemNoRecurse_AVL(mAVL,6)->key);
    //---test Destroy---
    Destroy_AVL(mAVL);
    printf("Test Destroy!\n");
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.对于二叉排序树,下面的说法( )是正确的。 A.二叉排序树是动态树表,查找不成功时插入新结点时,会引起树的重新分裂和组合 B.对二叉排序树进行层序遍历可得到有序序列 C.用逐点插入法构造二叉排序树时,若先后插入的关键字有序,二叉排序树的深度最大 D.在二叉排序树中进行查找,关键字的比较次数不超过结点数的1/2 2.在有n个结点且为完全二叉树的二叉排序树中查找一个键值,其平均比较次数的数量级为( )。 A.O(n) B.O(log2n) C.O(n*log2n) D.O(n2) 3.静态查找与动态查找的根本区别在于( )。 A. 它们的逻辑结构不一样 B. 施加在其上的操作不同 C. 所包含的数据元素类型不一样 D. 存储实现不一样 4.已知一个有序表为{12,18,24,35,47,50,62,83,90,115,134},当折半查找值为90的元素时,经过( )次比较后查找成功。 A.2 B.3 C.4 D.5 5.已知数据序列为(34,76,45,18,26,54,92,65),按照依次插入结点的方法生成一棵二叉排序树,则该树的深度为( )。 A. 4 B. 5 C. 6 D. 7 6.设散列表表长m=14,散列函数H(k)=k mod 11 。表中已有15,38,61,84四个元素,如果用线性探测法处理冲突,则元素49的存储地址是( )。 A. 8 B. 3 C. 5 D. 9 7. 平衡二叉树查找效率呈( )数量级。 A. 常数阶 B. 线性阶 C. 对数阶 D. 平方阶 8. 设输入序列为{20,11,12,…},构造一棵平衡二叉树,当插入值为12的结点时发生了不平衡,则应该进行的平衡旋转是( )。 A. LL B. LR C. RL D. RR 二、填空题(每空3分,共24分)。 1.在有序表A[1..18]中,采用二分查找算法查找元素值等于A[7]的元素,所比较过的元素的下标依次为 。 2.利用逐点插入法建立序列(61,75,44,99,77,30,36,45)对应的二叉排序树以后,查找元素36要进行 次元素间的比较,查找序列为 。 3. 用顺序查找法在长度为n的线性表中进行查找,在等概率情况下,查找成功的平均比较次数是 。 4. 二分查找算法描述如下: intSearch_Bin(SST ST, KT key) { low=1 ; high=ST. length; while(low<=high) { mid=(low+high)/2; if(key==ST.elem[mid].key) return mid; else if(key<ST.elem[mid].key) ; else ; } return 0; } 5.链式二叉树的定义如下: typedef struct Btn{ TElemType data; ; }BTN ,*BT; 6.在有n个叶子结点的哈夫曼树中,总结点数是 。 三、综合题(共52分)。 1. (共12分)假定关键字输入序列为19,21,47,32,8,23,41,45,40,画出建立二叉平衡树的过程。 2. (共15分)有关键字{13,28,31,15,49,36,22,50,35,18,48,20},Hash 函数为H=key mod 13,冲突解决策略为链地址法,请构造Hash表(12分),并计算平均查找长度(3分)。 ASL= 3. (共10分)设关键字码序列{20,35,40,15,30,25},给出平衡二叉树的构造过程。 4. (共15分)设哈希表长为m=13,散列函数为H(k)=k mod 11,关键字序列为5,7,16,12,11,21,31,51,17,81;试求:散列后的表中关键字分布(假定解决冲突的方法为线性探测再散列法);求平均查找长度ASL;计算该表的装填因子。 (1)按要求求哈希表(10分): 0 1 2 3 4 5 6 7 8 9 10 11 12 (2)计算ASL(3分): ASL= (3)计算装填因子(2分):装填因子=

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值