zoukankan      html  css  js  c++  java
  • AVL平衡二叉树

    平衡二叉树

    二叉树中所有结点的平衡因子BF的绝对值均小于等于1,即:(|BF|leq1)。平衡因子是,结点的左子树高度减去右子树的高度。平衡因子BF绝对值大于1表示二叉树失衡。

    插入失衡

    两种情况:

    1. 结点的平衡因子是1,向该结点的左子树插入结点,该结点的平衡因子变为2,导致失衡;
    2. 结点的平衡因子是-1,向该结点的右子树插入结点,该结点的平衡因子变为-2,导致失衡。

    如何解决失衡?

    关键问题是要找到失衡结点,离插入结点最近的失衡结点。

    失衡结点的特点:

    • 一定是插入结点的祖父结点
    • 插入结点时一定经过失衡结点

    解决办法:

    采用递归的方法进行插入,插入成功后会进行回代,因此在回代的过程中可以判断结点是否失衡,从而能够找到离插入结点最近的失衡结点。

    /*
    1、判断二叉树是否失衡,若失衡返回true,否则返回false
    2、若二叉树失衡,则返回离插入结点最近的结点
    */
    bool IsBalanced(BTNode<T> *&T,T key)
    {
        if(!T)
        {
            //未找到值为key的结点,进行插入
            Insert(key);
            return true;
        }
        else if(T->data==key)
        {
            return false;//找到结点key,不可插入
        }
        else if(T->data>key)
        {
            bool temp=IsBalanced(T->lchild,key);//如果temp为真,则表示结点插入到T的左子树
            if(temp)
            {
                //判断T的平衡因子,若等于1,则需要调整
            }
        }
        else
        {
            //同上
        }
    }
    

    附上完整代码:

    #include <iostream>
    using namespace std;
    
    //结点结构
    template <class T>
    class BTNode
    {
    public:
        //结点数据
        T data;
        //左右孩子指针
        BTNode<T> *lchild, *rchild;
        //添加平衡因子
        int BF;
    
    public:
        //构造函数
        BTNode(T D, int bf = 0, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), BF(bf), lchild(l), rchild(r) {}
    };
    
    //AVL平衡二叉树
    template <class T>
    class AVLTree
    {
        //私有属性
    private:
        //二叉树根节点
        BTNode<T> *root;
    
    private:
        //销毁二叉树
        void Destory(BTNode<T> *&rt)
        {
            if(rt)
            {
                this->Destory(rt->lchild);
                this->Destory(rt->rchild);
                delete rt;
            }
        }
        //二叉树查找
        //和二叉排序树的查找方法一样
        bool SearchAVL(BTNode<T> *rt, T key, BTNode<T> *&p, BTNode<T> *f = NULL)
        {
            if (!rt) //查找失败,返回false
            {
                p = f; //p指向查找路径上最后访问的元素
                return false;
            }
            else if (rt->data == key) //查找成功,返回true
            {
                p = rt; //p指向查找到的元素
                return true;
            }
            else if (rt->data > key)
            {
                return this->SearchAVL(rt->lchild, key, p, rt);
            }
            else
            {
                return this->SearchAVL(rt->rchild, key, p, rt);
            }
        }
        //左旋处理
        void L_Rotate(BTNode<T> *&p)
        {
            BTNode<T> *R = p->rchild; //R指向p的左孩子
            p->rchild = R->lchild;    //p的右孩子指向R的左孩子
            R->lchild = p;            //R的左孩子指向p
            p = R;                    //该二叉树的根节点变为R
        }
        //右旋处理
        void R_Rotate(BTNode<T> *&p)
        {
            BTNode<T> *L = p->lchild;
            p->lchild = L->rchild;
            L->rchild = p;
            p = L;
        }
        //左平衡处理,已知结点的平衡因子是+2,因此必定是在该结点的左子树插入的结点
        //二叉排序树的根节点平衡因子的绝对值大于1,需进行平衡处理
        void LeftBalance(BTNode<T> *&p)
        {
            BTNode<T> *L = p->lchild; //L指向p的左孩子
            /*
            判断L的平衡因子
            若平衡因子为1,表示新节点插入在L的左子树
            若平衡因子为-1,表示新节点插入在L的右子树
            */
            switch (L->BF)
            {
            case 1: //结点插入在L的左子树,需进行右旋处理
                this->R_Rotate(p);
                p->BF = 0;
                p->rchild->BF = 0; //右旋处理后,需改变旋转结点的平衡因子
                break;
            case -1:
            { //结点插入在L的右子树,需进行双旋处理
                BTNode<T> *L_R = L->rchild;
                switch (L_R->BF)
                {
                case 1: //结点插入在L_R的左子树
                    p->BF = -1;
                    L->BF = 0;
                    break;
                case 0: //结点L_R就是新插入的结点
                    p->BF = 0;
                    L->BF = 0;
                    break;
                case -1: //结点插入在L_R的右子树
                    p->BF = 0;
                    L->BF = 1;
                    break;
                }
                L_R->BF = 0;
                this->L_Rotate(L); //先左旋处理
                this->R_Rotate(p); //后右旋处理
                break;
            }
            }
        }
        //右平衡处理,已知结点的平衡因子是-2,因此必定是在该结点的右子树插入的结点
        void RightBalance(BTNode<T> *&p)
        {
            BTNode<T> *R = p->rchild;
            switch (R->BF)
            {
            case 1:
            { //新节点插入在R的左子树上,需进行双旋处理
                BTNode<T> *R_L = R->lchild;
                switch (R_L->BF)
                {
                case 1: //结点插入在R_L的左子树上
                    p->BF = 0;
                    R->BF = -1;
                    break;
                case 0: //R_L就是新插入的结点
                    p->BF = 0;
                    R->BF = 0;
                    break;
                case -1: //结点插入在R_L的右子树上
                    p->BF = 1;
                    R->BF = 0;
                    break;
                }
                R_L->BF = 0;
                this->R_Rotate(R); //先右旋处理
                this->L_Rotate(p); //后左旋处理
                break;
            }
            case -1: //新节点插入在R的右子树上,需进行左旋处理
                p->BF = 0;
                R->BF = 0;
                this->L_Rotate(p);
                break;
            }
        }
        //向二叉树中插入结点,并保持平衡
        bool InsertAVL(BTNode<T> *&rt, T key, bool &taller) //taller用来记录二叉树是否长高
        {
            if (!rt) //表示未在二叉树中找到结点值为key的结点,需插入结点
            {
                rt = new BTNode<T>(key, 0, NULL, NULL); //将新节点赋值给rt指针
                taller = true;
                return true;
            }
            else if (rt->data == key) //存在key,返回false
            {
                taller = false;
                return false;
            }
            else if (rt->data > key)
            {
                if (!this->InsertAVL(rt->lchild, key, taller)) //未插入结点
                {
                    return false;
                }
                if (taller) //二叉树长高,表示递归回到rt结点
                {
                    switch (rt->BF)
                    {
                    case 1: //结点rt的平衡因子为1,而又在左子树新插入结点,故结点rt失衡,需调整
                        this->LeftBalance(rt);
                        taller = false; //维护状态,在失衡结点调整后,其祖父结点的平衡因子不会变,故不用更改,结束此模块递归
                        break;
                    case 0: //结点rt的平衡因子为0,在左子树插入结点,结点rt不会失衡,不用调整
                        rt->BF = 1;
                        taller = true; //插入新节点,二叉树高度增加,继续此模块递归,找到失衡结点
                        break;
                    case -1: //结点rt的平衡因子为-1,在左子树插入结点,结点rt不会失衡,不用调整
                        rt->BF = 0;
                        taller = false; //插入新节点,二叉树高度未增,结束此模块递归
                        break;
                    }
                }
                return true;
            }
            else
            {
                if (!this->InsertAVL(rt->rchild, key, taller)) //未插入结点
                {
                    return false;
                }
                if (taller) //二叉树长高,表示递归回到rt结点
                {
                    switch (rt->BF)
                    {
                    case 1: //结点rt的平衡因子为1,而又在右子树新插入结点,故结点rt不会失衡
                        rt->BF = 0;
                        taller = false; //插入新节点,二叉树高度未增,结束此模块递归
                        break;
                    case 0: //结点rt的平衡因子为0,在右子树插入结点,结点rt不会失衡,不用调整
                        rt->BF = -1;
                        taller = true; //插入新节点,二叉树高度增加,继续此模块递归,找到失衡结点
                        break;
                    case -1: //结点rt的平衡因子为-1,在右子树插入结点,结点rt会失衡,用调整
                        this->RightBalance(rt);
                        taller = false; //维护状态,在失衡结点调整后,其祖父结点的平衡因子不会变,故不用更改,结束此模块递归
                        break;
                    }
                }
                return true;
            }
        }
        //前序遍历
        void PreOrder(BTNode<T> *rt)
        {
            if (rt)
            {
                cout << rt->data << " ";
                this->PreOrder(rt->lchild);
                this->PreOrder(rt->rchild);
            }
        }
        //中序遍历
        void InOrder(BTNode<T> *rt)
        {
            if(rt)
            {
                this->InOrder(rt->lchild);
                cout<<rt->data<<" ";
                this->InOrder(rt->rchild);
            }
        }
    
    public:
        //构造函数
        AVLTree() : root(NULL) {}
        //拷贝构造函数
        AVLTree(const AVLTree<T> &t) {}
        //销毁二叉树
        void Destory() 
        {
            this->Destory(this->root);
            this->root=NULL;
        }
        //析构函数
        ~AVLTree()
        {
            this->Destory(this->root);
        }
        //前序遍历
        void PreOrder()
        {
            this->PreOrder(this->root);
        }
        //中序遍历
        void InOrder()
        {
            this->InOrder(this->root);
        }
        //二叉树查找
        bool Search(T key, BTNode<T> *&p = NULL)
        {
            return this->SearchAVL(this->root, key, p, NULL);
        }
        //插入操作
        bool Insert(T key)
        {
            bool p;
            return this->InsertAVL(this->root, key, p);
        }
    };
    
    int main()
    {
        AVLTree<int> temp;
        for (int i = 0; i < 10; i++)
        {
            temp.Insert(i);
        }
        temp.PreOrder();
        cout<<endl;
        temp.InOrder();
        cout<<endl;
    
        system("pause");
        return 0;
    }
    
  • 相关阅读:
    jquery.autocomplete 使用解析
    《SEO实战密码》
    Thinkphp 生成的验证码不显示问题解决
    css去除li的小圆点
    css隐藏input边框阴影
    HBuilde 申请密钥证书
    请求筛选模块被配置为拒绝包含 hiddenSegment 节的 URL 中的路径
    js 判断屏幕下拉上滑操作
    gis 从WGS84转百度
    GIS个坐标系转换
  • 原文地址:https://www.cnblogs.com/cqy-wt1124/p/12821277.html
Copyright © 2011-2022 走看看