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;
    }
    
  • 相关阅读:
    Civil 3D 二次开发 创建Civil 3D 对象—— 01 —— 创建几何空间点
    Civil 3D 二次开发 创建Civil 3D 对象—— 00 ——
    Civil 3D 二次开发 创建AutoCAD对象—— 01 —— 创建直线
    Civil 3D 二次开发 新建CLR项目出现错误C2143
    Civil 3D 二次开发 创建AutoCAD对象—— 00 ——
    了解AutoCAD对象层次结构 —— 6 ——块表记录
    datepicker97使用
    使用angular 外接 templateUrl,使用ng-include
    angularJs 遮罩
    网上找的有关css兼容问题
  • 原文地址:https://www.cnblogs.com/cqy-wt1124/p/12821277.html
Copyright © 2011-2022 走看看