zoukankan      html  css  js  c++  java
  • AVL树

    2017-08-29 14:35:55

    writer:pprp

    AVL树就是带有平衡条件的二叉查找树。每个节点的左子树和右子树高度相差最多为1的二叉查找树

    空树的高度定为-1

    对树的修正称为旋转

    对内部的来说是双旋,对外部的调整修正是单旋

    ----------------------------------------------------------------------------------------------------------------

    由于一次旋转总能解决问题,因此编写非递归程序要比编写递归程序快很多,但是非递归方式编写比较难

    还是很多人都选择递归的方式,这里也选择递归的方式,比较容易理解;

    代码如下:(还没有完全写好,删除部分不太理解)

    /*
    @theme:AVL tree
    @writer:pprp
    @begin:14:32
    @end:16:26
    @declare:带有平衡条件的二叉查找树,这里不需要一个创建节点的函数,
    因为相关操作已经在Insert函数中完成了
    @date:2017/8/29
    */
    
    #include <bits/stdc++.h>
    
    using namespace std;
    struct AvlNode;
    typedef struct AvlNode* Position;
    typedef struct AvlNode* AvlTree;
    
    AvlTree MakeEmpty(AvlTree T);
    Position Find(int X, AvlTree T);
    Position FindMin(AvlTree T);
    Position FindMax(AvlTree T);
    AvlTree Insert(int X, AvlTree T);
    AvlTree Delete(int X, AvlTree T);
    
    static Position SingleRotateWithLeft(Position);
    static Position DoubleRotateWithLeft(Position);
    static Position SingleRotateWithRight(Position);
    static Position DoubleRotateWithRight(Position);
    
    //AVL tree节点声明
    struct AvlNode
    {
        int element;
        AvlTree left;
        AvlTree right;
        int Height;
    };
    
    //一个快速的函数来返回节点高度
    static int Height(Position P)
    {
        if(P == NULL)
            return -1;
        else
            return P->Height;
    }
    
    //向AVL树中插入节点的函数
    AvlTree Insert(int X, AvlTree T)
    {
        //如果节点为空,建立然后返回一个单节点的树
        if(T == NULL)
        {
            T = new AvlNode();
            //如果失败
            if(T == NULL)
            {
                cout << "Out of place!" << endl;
            }
            else
            {
                T->element = X;
                T->Height = 0;
                T->left = T->right = NULL;
            }
        }
        else if(X < T->element) //如果头结点不为空
        {
            T->left = Insert(X,T->left);
            //question
            //如果不满足AVL tree的要求了,且左侧高于右侧,对左侧进行处理
            if(Height(T->left) - Height(T->right) == 2)
            {
                if(X < T->left->element)//如果小于左边
                    T = SingleRotateWithLeft(T);//进行左侧的单旋
                else
                    T = DoubleRotateWithLeft(T);//进行左侧的双旋
            }
        }
        else if(X > T->element)
        {
            T->right = Insert(X, T->right);
            //如果右侧高于左侧进行旋转
            if(Height(T->right) - Height(T->left) == 2)
            {
                if(X > T->right->element)
                    T = SingleRotateWithRight(T);
                else
                    T =  DoubleRotateWithRight(T);
            }
        }
        //else X is in the tree already , we'll do nothing
        T->Height = max(Height(T->left),Height(T->right)) + 1;
        return T;
    }
    
    //执行单旋转的左边 LL
    static Position SingleRotateWithLeft(Position K2)
    {
        Position K1;
        K1 = K2->left;
        K2->left = K1->right;
        K1->right = K2;
    
        K2->Height = max(Height(K2->left),Height(K2->right))+1;
        K1->Height = max(Height(K1->left),Height(K1->right))+1;
    
        return K1;
    }
    
    //执行双旋转的左边 LR
    static Position DoubleRotateWithLeft(Position K3)
    {
        //rotate between K1 and K2
        K3->left = SingleRotateWithRight(K3->left);
        //rotate between K3 and K2
        return SingleRotateWithLeft(K3);
    }
    
    //执行单旋转的右边 RR
    static Position SingleRotateWithRight(Position K1)
    {
        Position K2;
    
        K2 = K1->left;
        K1->left = K2->right;
        K2->right = K1;
    
        K1->Height = max(Height(K1->right),Height(K2->left))+1;
        K2->Height = max(Height(K2->right),Height(K2->left))+1;
    
        return K2;
    }
    //执行双旋转的右边 RL
    static Position DoubleRotateWithRight(Position K3)
    {
        K3->right = SingleRotateWithLeft(K3->right);
        return SingleRotateWithRight(K3);
    }
    
    //进行中序遍历
    void MidPrint(AvlTree T)
    {
        if(T != NULL)
        {
            MidPrint(T->left);
            cout << T->element << " ";
            MidPrint(T->right);
        }
    }
    
    //查找函数,返回一个指针
    Position Find(int X, AvlTree T)
    {
        if(T == NULL)
            return NULL;
        if(X < T->element)
            return Find(X, T->right);
        else if(X > T->element)
            return Find(X, T->left);
        else
            return T;
    }
    
    //找到最大值
    Position FindMax(AvlTree T)
    {
        if(T == NULL)
            return NULL;
        else if(T->right == NULL)
            return T;
        else
            return FindMax(T->right);
    }
    
    //找到最小值
    Position FindMin(AvlTree T)
    {
        if(T == NULL)
            return NULL;
        else if(T->left == NULL)
            return T;
        else
            return FindMin(T->left);
    }
    
    //删除节点,返回根节点
    AvlTree Delete(int X, AvlTree T)
    {
        AvlTree tmp = Find(X,T);
        if(T == NULL || tmp == NULL)
            return NULL;
        if(X < T->element)//如果在左子树中
        {
            T->left = Delete(X,T->left);
            //开始调整由于删除带来的影响
            if(Height(T->right) - Height(T->left) == 2)
            {
                AvlTree K = T->right;//因为右边高度比较高
                if(Height(K->left) > Height(K->right))
                    DoubleRotateWithRight(T);
                else
                    SingleRotateWithRight(T);
            }
        }
        else if(X > T->element) //如果在右子树中
        {
            T->right = Delete(X,T->right);
            if(Height(T->left) - Height(T->right) == 2)
            {
                AvlTree K = T->left;
                if(Height(K->right) > Height(K->left))
                    DoubleRotateWithLeft(T);
                else
                    SingleRotateWithLeft(T);
            }
        }
        else if(X == T->element)
        {
            // 如果两个孩子非空
            if(T->left && T->right)
            {
                //维护AVL树特性:本来可以选择两种方式进行删除
                //现在要优先删除高度比较高的子树
                if(Height(T->left) > Height(T->right))
                {
                    AvlTree Max = FindMax(T->left); //找到最大值
                    T->element = Max->element;   //将内容进行替换
                    delete(Max); //删除该节点
                    Max = NULL;
                }
                else
                {
                    AvlTree Min = FindMin(T->right);
                    T->element = Min->element;
                    delete(Min);//删除该节点
                    Min = NULL;
                }
            }
            else //如果有一个子节点或者没有子节点
            {
                AvlTree tmp = T;
                T = T->left == NULL ? T->right:T->left;
                delete(tmp);
            }
        }
        return T;
    }
    
    //清空整个树
    AvlTree MakeEmpty(AvlTree T)
    {
        if(T!= NULL)
        {
            MakeEmpty(T->right);
            MakeEmpty(T->left);
            delete(T);
        }
    }
    
    int main()
    {
    
        AvlTree T;
        int n, tmp;
        cin >> n;
        for(int i = 0 ; i < n ; i++)
        {
            cin >> tmp;
            T = Insert(tmp,T);
        }
    
        return 0;
    }

     

  • 相关阅读:
    利用virtual box安装ubuntu16.4,没有继续(下一步)的解决方案
    最好用的几个谷歌镜像(推荐理由:无广告)
    vs2017和vs2019专业版和企业版
    c# List根据某个属性进行分类,变成以属性名称作为分类的多个List
    vs2015安装编辑神器:resharper10.0
    c# 正则表达式替换字符串中常见的特殊字符
    IL中间语言指令大全
    c#进阶一:使用ILDASM来查看c#中间语言
    SQL server脚本语句积累
    SQLServer事务在C#当中的应用
  • 原文地址:https://www.cnblogs.com/pprp/p/7449168.html
Copyright © 2011-2022 走看看