AVL树的实现

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;

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树是一种自平衡二叉搜索树,可以用来实现字典类型。在实现字典类型时,我们可以将键值对存储在AVL树的节点中,其中键作为节点的关键字,值则作为节点的附加数据。 下面是一个简单的AVL树实现字典类型的Python代码: ```python class AVLNode: def __init__(self, key, val): self.key = key self.val = val self.left = None self.right = None self.height = 1 class AVLTree: def __init__(self): self.root = None def insert(self, key, val): self.root = self._insert(self.root, key, val) def _insert(self, node, key, val): if not node: return AVLNode(key, val) if key < node.key: node.left = self._insert(node.left, key, val) elif key > node.key: node.right = self._insert(node.right, key, val) else: node.val = val node.height = 1 + max(self._height(node.left), self._height(node.right)) balance = self._get_balance(node) if balance > 1 and key < node.left.key: return self._right_rotate(node) if balance < -1 and key > node.right.key: return self._left_rotate(node) if balance > 1 and key > node.left.key: node.left = self._left_rotate(node.left) return self._right_rotate(node) if balance < -1 and key < node.right.key: node.right = self._right_rotate(node.right) return self._left_rotate(node) return node def search(self, key): node = self._search(self.root, key) if node: return node.val else: return None def _search(self, node, key): if not node: return None if key == node.key: return node if key < node.key: return self._search(node.left, key) else: return self._search(node.right, key) def _height(self, node): if not node: return 0 return node.height def _get_balance(self, node): if not node: return 0 return self._height(node.left) - self._height(node.right) def _left_rotate(self, node): new_root = node.right node.right = new_root.left new_root.left = node node.height = 1 + max(self._height(node.left), self._height(node.right)) new_root.height = 1 + max(self._height(new_root.left), self._height(new_root.right)) return new_root def _right_rotate(self, node): new_root = node.left node.left = new_root.right new_root.right = node node.height = 1 + max(self._height(node.left), self._height(node.right)) new_root.height = 1 + max(self._height(new_root.left), self._height(new_root.right)) return new_root ``` 在这个实现中,我们定义了AVLNode类来表示AVL树的节点。每个节点包含一个键、一个值、左右子树指针以及节点高度。AVLTree类是AVL树实现,包含了插入、搜索、左旋和右旋等基本操作。 在insert操作中,我们首先按照二叉搜索树的规则找到要插入的位置。然后更新节点高度,并计算平衡因子。如果平衡因子超过了1或-1,我们就需要进行旋转来保持AVL树的平衡。 在search操作中,我们按照二叉搜索树的规则搜索键值对应的节点,并返回其值。 这个AVL树实现可以用来实现字典类型。我们可以将键值对存储在AVL树的节点中,并通过搜索操作来查找键对应的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值