AVL树的基本实现

来源:互联网 发布:泰牛程序员官网 编辑:程序博客网 时间:2024/05/17 23:47

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,左单旋
个

我们在图中可以看出来,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,右单旋

方式

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

代码实现:

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,左右双旋

广东省

我们从图中可以看到,左右双旋进行了一次左单旋,进行了一次右单旋
那么它的平衡因子是怎么调整的呢,
我们把平衡因子的调整分为三种情况
1,subLR没有左孩子
韩国海军

2,subLR没有右孩子
大幅度

3,subLR有左孩子和右孩子或者左右孩子都没有
似懂非懂

代码实现

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树需要旋转,怎么判断该树是哪种旋转呢?我们在这里也可以通过平衡因子判断。
大幅度
我们通过这张图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();}
原创粉丝点击