AVL树的基本实现

AVL树(高度平衡的二叉搜索树),它可以保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度

AVL树的性质
1,左子树和右子树的高度之差的绝对值不超过1
2,树中的每个左子树和右子树都是AVL树
3,每个结点都有一个平衡因子,任意一个结点的平衡因子是-1,0,1(每个结点的平衡因子等于右子树的高度减去左子树的高度)

AVL树的效率:一颗AVL树有N个结点,它的高度可以保持在lgN,其中插入删除查找的时间复杂度也为lgN(需要注意的是lg在这里表示的是以2为底)

首先我们定义AVLTreeNode的结点
在这里我们定义的是一个三叉链,作用后面会用到

template<class K,class V>
struct AVLTreeNode
{
    AVLTreeNode<K,V>* _left;
    AVLTreeNode<K,V>* _right;
    AVLTreeNode<K,V>* _parent;

    V _value;
    K _key;
    int _bf;
    AVLTreeNode(const K& key,const V& value)
        :_left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _key(key)
        , _bf(0)
        , _value(value)
    {}
};

我们先看一下插入的四种旋转的方式:
1,左单旋
《AVL树的基本实现》

我们在图中可以看出来,parent的平衡因子是2所以我们需要对它进行旋转,我们将subRL给parent的_right,将parent给subR的_left,这样就旋转好了吗?
当然没有我们并不知道原来的parent是根节点还是一颗子树,所以我们要在parent给subR的_left之前要定义一个变量parentparent保存parent 的_parent,如果parentparent为空,那么就说明之前parent是根节点,那么旋转结束之后subR就是旋转结束后这棵树的根节点,如果parentparent不为空,那么就说明这棵树只是一颗子树,如果parent在parentparent的_left那么就把subR给parentparent的_left,反之将subR给parentparent的_right。(这里要记住这是三叉链,我们要把每个都链起来)

代码实现:

void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;
        subR->_left = parent;
        Node* parentparent = parent->_parent;
        parent->_parent = subR;

        if (parentparent == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (parentparent->_left == parent)
            {
                parentparent->_left = subR;
                subR->_parent = parentparent;
            }
            else
            {
                parentparent->_right = subR;
                subR->_parent = parentparent;
            }
        }
        subR->_bf = parent->_bf = 0;
    }

2,右单旋

《AVL树的基本实现》

思想和左单旋相同,如果理解了左单旋,右单旋自然也就理解了

代码实现:

void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;

        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;

        subL->_right = parent;
        Node* parentparent = parent->_parent;
        parent->_parent = subL;

        if (parentparent == NULL)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (parentparent->_left == parent)
            {
                parentparent->_left = subL;
                subL->_parent = parentparent;
            }
            else
            {
                parentparent->_right = subL;
                subL->_parent = parentparent;
            }
        }
        subL->_bf = parent->_bf = 0;
    }

3,左右双旋

《AVL树的基本实现》

我们从图中可以看到,左右双旋进行了一次左单旋,进行了一次右单旋
那么它的平衡因子是怎么调整的呢,
我们把平衡因子的调整分为三种情况
1,subLR没有左孩子
《AVL树的基本实现》

2,subLR没有右孩子
《AVL树的基本实现》

3,subLR有左孩子和右孩子或者左右孩子都没有
《AVL树的基本实现》

代码实现

void RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = parent->_right;
        int bf = subLR->_bf;

        RotateL(parent->_left);
        RotateR(parent);

        if (bf == 1)//subLR没有左孩子
        {
            parent->_bf = 0;
            subL->_bf = -1;
        }
        else if (bf == -1)//subLR没有右孩子
        {
            subL->_bf = 0;
            parent->_bf = 1;
        }
        else//subLR有左孩子和右孩子或者左右孩子都没有
        {
            subL->_bf = parent->_bf = 0;
        }

        subLR->_bf = 0;
    }

4,右左双旋
右左双旋跟左右双旋的算法思想相同,如果理解了上一个,这个可以自己画图理解一下
代码实现:

    void RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;

        RotateR(parent->_right);
        RotateL(parent);

        if (bf == 1)//subRL没有左孩子
        {
            subR->_bf = 0;
            parent->_bf = -1;
            subRL->_bf = 0;
        }
        else if (bf == -1)////subRL没有右孩子
        {
            subR->_bf = 0;
            parent->_bf = 1;
            subRL->_bf = 0;
        }
        else//subRL有左孩子和右孩子或者左右孩子都没有
        {
            parent->_bf = subRL->_bf = subR->_bf = 0;
        }
    }

插入的实现:
思想:
1,先遍历这棵树,查找要插入的地方
2,new一个新的结点,并连接起来
3,调节平衡因子:
我们在左边添加结点,该结点的父亲的平衡因子要减1
在右边添加结点,该结点的父亲的平衡因子要加1;
那么我们怎么样看插入就结点是否影响祖父呢,我们在这里可以找到平衡因子的规律:如果该结点的父亲的平衡因子从0变到了1或者-1,那么一定会影响祖父,如果该结点的父亲的平衡因子变为了0,那么该结点的插入只会影响父亲的平衡因子。
如果结点的平衡因子变为了2或者-2,那么该AVL树需要旋转,怎么判断该树是哪种旋转呢?我们在这里也可以通过平衡因子判断。
《AVL树的基本实现》
我们通过这张图parent为+2并且他的右孩子(subR)为正那么就是左单旋,如果它的右孩子(subR)为负,那么就是右左双旋。
如果parent为-2并且它的左孩子(subL)为负,那么它就是右单旋
如果它的左孩子(subL)为正,那么它就是左右双旋。
总结一下就是,同号是单旋,异号是双旋。

bool Insert(const K& key,const V& value)
    {
        if (_root == NULL)
        {
            _root = new Node(key,value);
            return true;
        }
        Node* cur = _root;
        Node* parent = NULL;
        while (cur)
        {
            if (cur->_key < key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }

        }
        //添加结点
        cur = new Node(key,value);
        if (parent->_key < key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }
        //平衡因子
        while (parent)
        {
            if (cur == parent->_left)
            {
                --(parent->_bf);
            }
            else
            {
                ++(parent->_bf);
            }

            if (parent->_bf == 0)
            {
                break;
            }
            else if (parent->_bf == 1 || parent->_bf == -1)
            {
                cur = parent;
                parent = cur->_parent;
            }
            else
            {
                //2或-2,就要旋转
                if (parent->_bf == -2)
                {
                    if (cur->_bf == -1)
                    {
                        RotateR(parent);
                    }
                    else
                    {
                        RotateLR(parent);
                    }
                }
                else
                {
                    if (cur->_bf == 1)
                    {
                        RotateL(parent);
                    }
                    else
                    {
                        RotateRL(parent);
                    }
                }
                break;
            }
        }
        return true;
    }

我们插入完成了,那么如何让判断这棵树是否是AVL树呢?
在这里我们写一个函数来实现:
算法思想:
判断是否是AVL树,我们必须要让这棵树满足AVL树的性质,即左子树和右子树的高度差的绝对值不能超过1,并且它的左子树和右子树也是AVL树。

我们首先实现一个函数求树的高度,然后让每棵树的右子树减去它的左子树。判断他们高度差的绝对值是否是不超过1.

    int Depth()
    {
        return _Depth(_root);
    }
    int _Depth(Node* root)
    {
        if (root == NULL)
        {
            return 0;
        }

        int left = _Depth(root->_left);
        int right = _Depth(root->_right);

        return left > right ? left + 1 : right + 1;

    }
    bool IsBalance()
    {
        return _IsBalance(_root);
    }

    bool _IsBalance(Node* root)//时间复杂度为N*N
    {
        if (root == NULL)
        {
            return 0;
        }

        int left = _Depth(root->_left);
        int right = _Depth(root->_right);

        return abs(right - left) < 2
            && _IsBalance(root->_left)
            && _IsBalance(root->_right);
    }

我们可以看到用递归实现判断是否是AVL树它的时间复杂度为N*N。
他把这棵树在求高度的时候遍历了一遍,递归的时候还在遍历,这样就使得该函数遍历了两遍,那么我们能否将这棵树的时间复杂度优化到O(N),我们可以想到斐波那契树时,我们倒着往上遍历,时间复杂度会低很多,那么我们的AVL树也可以先找到最左结点,然后倒着向上判断
,把每一层判断的高度的结果返回给上一层,所以我们的depth要加上引用。
代码实现:

//优化到O(N),把高度返回给上一层
    bool _IsBalance(Node* root, int& depth)
    {
        if (root == NULL)//先判断是否为空
        {
            depth = 0;
            return true;
        }

        int leftDepth = 0;
        if (_IsBalance(root->_left, leftDepth) == false)//如果它不平衡直接return false
            return false;
        int rightDepth = 0;

        if (_IsBalance(root->_right, rightDepth) == false)
            return false;

        if ((rightDepth - leftDepth) != root->_bf)
        {
            cout << "bf 异常" << root->_key << endl;
            //return false;
        }

        depth = rightDepth > leftDepth ? rightDepth + 1 : leftDepth + 1;
        return abs(rightDepth - leftDepth) < 2;
    }

完整代码:

#include<iostream>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
    AVLTreeNode<K,V>* _left;
    AVLTreeNode<K,V>* _right;
    AVLTreeNode<K,V>* _parent;

    V _value;
    K _key;
    int _bf;
    AVLTreeNode(const K& key,const V& value)
        :_left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _key(key)
        , _bf(0)
        , _value(value)
    {}
};

template<class K,class V>
class AVLTree
{
    typedef AVLTreeNode<K,V> Node;
public:
    AVLTree()
        :_root(NULL)
    {}

    bool Insert(const K& key,const V& value)
    {
        if (_root == NULL)
        {
            _root = new Node(key,value);
            return true;
        }
        Node* cur = _root;
        Node* parent = NULL;
        while (cur)
        {
            if (cur->_key < key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }

        }
        //添加结点
        cur = new Node(key,value);
        if (parent->_key < key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }
        //平衡因子
        while (parent)
        {
            if (cur == parent->_left)
            {
                --(parent->_bf);
            }
            else
            {
                ++(parent->_bf);
            }

            if (parent->_bf == 0)
            {
                break;
            }
            else if (parent->_bf == 1 || parent->_bf == -1)
            {
                cur = parent;
                parent = cur->_parent;
            }
            else
            {
                //2或-2,就要旋转
                if (parent->_bf == -2)
                {
                    if (cur->_bf == -1)
                    {
                        RotateR(parent);
                    }
                    else
                    {
                        RotateLR(parent);
                    }
                }
                else
                {
                    if (cur->_bf == 1)
                    {
                        RotateL(parent);
                    }
                    else
                    {
                        RotateRL(parent);
                    }
                }
                break;
            }
        }
        return true;
    }

    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;
        subR->_left = parent;
        Node* parentparent = parent->_parent;
        parent->_parent = subR;

        if (parentparent == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (parentparent->_left == parent)
            {
                parentparent->_left = subR;
                subR->_parent = parentparent;
            }
            else
            {
                parentparent->_right = subR;
                subR->_parent = parentparent;
            }
        }
        subR->_bf = parent->_bf = 0;
    }

    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;

        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;

        subL->_right = parent;
        Node* parentparent = parent->_parent;
        parent->_parent = subL;

        if (parentparent == NULL)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (parentparent->_left == parent)
            {
                parentparent->_left = subL;
                subL->_parent = parentparent;
            }
            else
            {
                parentparent->_right = subL;
                subL->_parent = parentparent;
            }
        }
        subL->_bf = parent->_bf = 0;
    }

    void RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;

        RotateR(parent->_right);
        RotateL(parent);

        if (bf == 1)
        {
            subR->_bf = 0;
            parent->_bf = -1;
            subRL->_bf = 0;
        }
        else if (bf == -1)
        {
            subR->_bf = 0;
            parent->_bf = 1;
            subRL->_bf = 0;
        }
        else
        {
            parent->_bf = subRL->_bf = subR->_bf = 0;
        }
    }
    void RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = parent->_right;
        int bf = subLR->_bf;

        RotateL(parent->_left);
        RotateR(parent);

        if (bf == 1)
        {
            parent->_bf = 0;
            subL->_bf = -1;
        }
        else if (bf == -1)
        {
            subL->_bf = 0;
            parent->_bf = 1;
        }
        else
        {
            subL->_bf = parent->_bf = 0;
        }

        subLR->_bf = 0;
    }
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }

    void _InOrder(Node* root)
    {
        if (root == NULL)
            return;

        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }

    int Depth()
    {
        return _Depth(_root);
    }
    int _Depth(Node* root)
    {
        if (root == NULL)
        {
            return 0;
        }

        int left = _Depth(root->_left);
        int right = _Depth(root->_right);

        return left > right ? left + 1 : right + 1;

    }
    //bool IsBalance()
    //{
    // return _IsBalance(_root);
    //}

    /*bool _IsBalance(Node* root)//时间复杂度为N*N { if (root == NULL) { return 0; } int left = _Depth(root->_left); int right = _Depth(root->_right); return abs(right - left) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right); }*/


    //优化到O(N),把高度返回给上一层
    bool _IsBalance(Node* root, int& depth)
    {
        if (root == NULL)//先判断是否为空
        {
            depth = 0;
            return true;
        }

        int leftDepth = 0;
        if (_IsBalance(root->_left, leftDepth) == false)//如果它不平衡直接return false
            return false;
        int rightDepth = 0;

        if (_IsBalance(root->_right, rightDepth) == false)
            return false;

        if ((rightDepth - leftDepth) != root->_bf)
        {
            cout << "bf 异常" << root->_key << endl;
            //return false;
        }

        depth = rightDepth > leftDepth ? rightDepth + 1 : leftDepth + 1;
        return abs(rightDepth - leftDepth) < 2;
    }
private:
    Node* _root;
};

void test()
{
    int a[] = { 16, 30, 7, 11, 9, 26, 18, 14, 19 }; AVLTree<int, int> tree; for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { tree.Insert(a[i], i); } tree.InOrder(); }
    原文作者:AVL树
    原文地址: https://blog.csdn.net/zhuohaiyy/article/details/78416263
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞