AVL树的实现

来源:互联网 发布:安倍 知乎 编辑:程序博客网 时间:2024/06/08 09:29

AVL树又名高度平衡的搜索二叉树,上一篇文章我们讲到二叉搜索树时,说到它存在一个问题:退化,这使得它的时间复杂度从O(lgN)降到了O(N)。为了解决这个问题,出现了一棵新的树,也就是AVLtree,我们先来看看它的性质:
1,它是一棵搜索 二叉树,所以满足每个节点的值大于左子树中任意节点的值,并且小于右子树中任意节点的值。
2,它是一棵平衡树,他要求每个节点的左右子树的深度之差不能超过1,即这棵树的倒数第二层节点是满的。
3,每一棵子树都是一棵AVL树;
4,每个节点都有一个平衡因子bf,取值为-1、0、1 。它的值等于右子树的深度减去左子树的深度。

AVL树节点的结构如下:

template<class K,class V>struct AVLTreeNode{    AVLTreeNode<K,V>* _left;    AVLTreeNode<K,V>* _right;    AVLTreeNode<K,V>* _parent;    K _key;    V _value;    int _bf;  //平衡因子    AVLTreeNode(const K& key,const V& value)        :_left(NULL),_right(NULL),_parent(NULL),_key(key),_value(value),_bf(0)    {}};

对于AVL树的操作,这里主要讲解一下插入
插入操作中,通过对平衡因子的判定来进行相应的旋转操作来改变树的结构。整个过程可以分为三个过程:1,寻找插入位置;2,插入;3,调整(重点也是难点)。对此我画了个流程图,如下:
这里写图片描述

代码如下:

    bool Insert(const K& key,const V& value)    {        if (_root == NULL)        {            _root = new Node(key, value);            return true;        }        Node* cur = _root;        Node* parent = cur;        while (cur)        {            if (key > cur->_key)            {                parent = cur;                cur = cur->_right;            }            else if (key < cur->_key)            {                parent = cur;                       cur = cur->_left;            }            else                return false;        }        //找到插入的位置   插入        cur = new Node(key, value);        cur->_parent = parent;        if (parent->_key > key)            parent->_left = cur;        else            parent->_right = cur;        //调整平衡因子        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   // parent->_bf == 2  /  == -2            {                //旋转                if (parent->_bf == 2)                {                    if (cur->_bf == 1)                    {                        RotateL(parent);                    }                    else                    {                        RotateRL(parent);                    }                }                else                {                    if (cur->_bf == 1)                    {                        RotateLR(parent);                    }                    else                    {                        RotateR(parent);                    }                }                break;            }        }        return true;    }

下面我们再一次来看一下四种旋转(LL, LR, RR, RL):
1,对于LL,在左旋之后,只需将该节点(parent)和右孩子根节点(subR)的平衡因子置为0即可。
这里写图片描述

代码如下:

void RotateL(Node* parent)    {        Node* subR = parent->_right;        Node* subRL = subR->_left;        parent->_right = subRL;        if (subRL)            subRL->_parent = parent;        subR->_left = parent;        Node* pparent = parent->_parent;        if (pparent)        {            parent->_parent = subR;                 if (pparent->_left == parent)                pparent->_left = subR;            else                pparent->_right = subR;        }        else            _root = subR;        subR->_parent = pparent;        subR->_bf = parent->_bf = 0;    }

2,对于RR,在右旋之后,只需将该节点(parent)和左孩子根节点(subL)的平衡因子置为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* pparent = parent->_parent;        if (pparent)        {            parent->_parent = subL;            if (pparent->_left == parent)                pparent->_left = subL;            else                pparent->_right = subL;        }        else            _root = subL;        subL->_parent = pparent;        subL->_bf = parent->_bf = 0;    }

3,对于LR,保存subLR的平衡因子,用于后面判断:如果为1,subRL的右孩子会补为parent的左孩子,subL的右节点无人补,是空,subL的bf置为-1,如果为-1,subLR的左孩子会补为subL的右孩子,而parent的左节点无人补,parent的bf置为1
这里写图片描述
代码如下:

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

4,对于RL,保存subRL的平衡因子,用于后面判断:如果为1,subRL的右孩子会补为subR的左孩子,parent的右节点无人补,是空,parent的bf置为-1,如果为-1,subRL的左孩子会补为parent的右孩子,而subR的左节点无人补,subR的bf置为1
这里写图片描述
代码如下:

void RotateRL(Node* parent)  //先旋转,后调整平衡因子    {        Node* subR = parent->_right;        Node* subRL = subR->_left;        int bf = subRL->_bf;        RotateR(parent->_right);        RotateL(parent);        if (1 == bf)   //subRL的右孩子会补为subR的左孩子,parent的右节点无人补,是空,bf置为-1        {            parent->_bf = -1;        }        else if (-1 == bf)   //subRL的左孩子会补为parent的右孩子,而subR的左节点无人补,bf置为1        {            subR->_bf = 1;        }        subRL->_bf = 0;    }

这样AVL树的插入就解决了,我们需要一个函数来判定该树是否是AVL树。这个简单,只需遍历整棵树,看他的平衡因子是否正确即可。代码如下:

    bool IsBalance()    {        int depth = 0;        return _IsBalance(_root, depth);    }    bool _IsBalance(Node* root, int& depth)    {        if (root == NULL)        {            depth = 0;            return true;        }        int leftDepth = 0;        int rightDepth = 0;        if (_IsBalance(root->_left, leftDepth) == false)            return false;        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;    K _key;    V _value;    int _bf;  //平衡因子    AVLTreeNode(const K& key,const V& value)        :_left(NULL),_right(NULL),_parent(NULL),_key(key),_value(value),_bf(0)    {}};template<class K,class V>class AVLTree{    typedef AVLTreeNode<K,V> Node;public:    AVLTree()        :_root(NULL)    {}    ~AVLTree()    {        _Delete(_root);    }    bool Insert(const K& key,const V& value)    {        if (_root == NULL)        {            _root = new Node(key, value);            return true;        }        Node* cur = _root;        Node* parent = cur;        while (cur)        {            if (key > cur->_key)            {                parent = cur;                cur = cur->_right;            }            else if (key < cur->_key)            {                parent = cur;                       cur = cur->_left;            }            else                return false;        }        //找到插入的位置   插入        cur = new Node(key, value);        cur->_parent = parent;        if (parent->_key > key)            parent->_left = cur;        else            parent->_right = cur;        //调整平衡因子        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   // parent->_bf == 2  /  == -2            {                //旋转                if (parent->_bf == 2)                {                    if (cur->_bf == 1)                    {                        RotateL(parent);                    }                    else                    {                        RotateRL(parent);                    }                }                else                {                    if (cur->_bf == 1)                    {                        RotateLR(parent);                    }                    else                    {                        RotateR(parent);                    }                }                break;            }        }        return true;    }    void InOrder()    {        _InOrder(_root);        cout << endl;    }    Node* Find(const K& x)    {        return _Find(x);    }    bool IsBalance()    {        int depth = 0;        return _IsBalance(_root, depth);    }protected:    bool _IsBalance(Node* root, int& depth)  //注意:depth引用    {        if (root == NULL)        {            depth = 0;            return true;        }        int leftDepth = 0;        int rightDepth = 0;        if (_IsBalance(root->_left, leftDepth) == false)            return false;        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;    }    Node* _Find(Node* root, const K& x)    {        while (root)        {            if (x > root->_key)                root = root->_right;            else if (x < root->_key)                root = root->_key;            else                return root;        }        return NULL;    }    void _InOrder(Node* root)    {        if (root == NULL)            return;        _InOrder(root->_left);        cout << root->_key << " ";        _InOrder(root->_right);    }    void _Delete(Node*& root)    {        if (root == NULL)            return;        _Delete(root->_left);        _Delete(root->_right);        delete root;        root = NULL;    }    int Depth(Node* root)    {        if (root == NULL)            return 0;        int leftDepth = Depth(root->_left);        int rightDepth = Depth(root->_right);        return leftDepth > rightDepth ?leftDepth + 1 : rightDepth + 1;    }    void RotateL(Node* parent)    {        Node* subR = parent->_right;        Node* subRL = subR->_left;        parent->_right = subRL;        if (subRL)            subRL->_parent = parent;        subR->_left = parent;        Node* pparent = parent->_parent;        if (pparent)        {            parent->_parent = subR;                 if (pparent->_left == parent)                pparent->_left = subR;            else                pparent->_right = subR;        }        else            _root = subR;        subR->_parent = pparent;        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* pparent = parent->_parent;        if (pparent)        {            parent->_parent = subL;            if (pparent->_left == parent)                pparent->_left = subL;            else                pparent->_right = subL;        }        else            _root = subL;        subL->_parent = pparent;        subL->_bf = parent->_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 RotateRL(Node* parent)  //先旋转,后调整平衡因子    {        Node* subR = parent->_right;        Node* subRL = subR->_left;        int bf = subRL->_bf;        RotateR(parent->_right);        RotateL(parent);        if (1 == bf)        {            subR->_bf = 0;            parent->_bf = -1;        }        else if (-1 == bf)        {            parent->_bf = 0;            subR->_bf = 1;        }        else        {            parent->_bf = subR->_bf = 0;        }            subRL->_bf = 0;    }private:    Node* _root;};void Test(){    AVLTree<int, int> t;    //int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};    int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)    {        t.Insert(a[i], i);        cout << a[i] << "IsBalance?" << t.IsBalance() << endl;    }    t.InOrder();    cout << "IsBalance?" << t.IsBalance() << endl;}
原创粉丝点击