关于c++:AVL树

3次阅读

共计 2177 个字符,预计需要花费 6 分钟才能阅读完成。

AVL 树性质

  • 它的左右子树都是 AVL 树
  • 左右子树高度之差的绝对值不超过 1(右子树高度 – 左子树高度)(也称为均衡因子)
  • 每个节点都有一个均衡因子
  • 个别 AVL 树都是三叉链(左右节点指针和父亲节点指针)
  • AVL 树高度为 O(logN)
  • AVL 树的工夫复杂度为 O(logN)。
  • 均衡因子的更新准则:

    • 如果新增节点在父节点的右边,则父节点的均衡因子减 1;顺次向上更新
    • 如果新增节点在父节点的左边,则父节点的均衡因子加 1;顺次向上更新
    • 直到以后节点的均衡因子为 0 才不向上持续更新了
    • 如果均衡因子为 - 2 或 2,则须要旋转。而后在判断是否须要持续更新。

AVL 树节点的定义形式

template<class K,class V>
struct AVLTreeNode      // 建设节点
{
    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;
    int _bf;  // 均衡因子
    pair<K, V> _kv; // 键值对,存储数据
    AVLTreeNode(const pair<K, V>& kv)   // 构造函数
        :_left(nullptr)
        ,_right(nullptr)
        ,_parent(nullptr)
        ,_bf(0)
        ,_kv(kv)
    {}};

AVL 树的四种旋转形式

为什么要旋转

  • 当插入一个节点时,直接插入可能会导致均衡被毁坏(插入节点的所有先人节点的均衡因子可能会扭转)
  • 这时就须要将数据进行旋转
  • 例如:当插入 30 节点时,这个树就不是 AVL 树了,所以将其进行旋转,失去左边的 AVL 树。

右单旋

右单旋代码实现

    // 右单旋
    void RotateR(Node* parent)  
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        Node* parent_parent = parent->_parent;
        parent->_left = subLR;
        if (subLR) subLR->_parent = parent;
        subL->_right = parent;
        parent->_parent = subL;
        if (parent == _root)
        {
            _root = subL;
            _root->_parent = nullptr;
        }
        else
        {if (parent_parent->_left == parent) parent_parent->_left = subL;
            else parent_parent->_right = subL;
            subL->_parent = parent_parent;
        }
        subL->_bf = 0;
        parent->_bf = 0;
    }

左单旋

左单旋代码实现

    // 左单旋
    void RotateL(Node* parent)  
    {
        Node* subR = parent->_right;  
        Node* subRL = subR->_left;    
        Node* parent_parent = parent->_parent;  
        parent->_right = subRL;
        if (subRL) subRL->_parent = parent;
        subR->_left = parent;
        parent->_parent = subR;
        if (parent == _root)
        {
            _root = subR;
            subR->_parent = nullptr;
        }
        else
        {if (parent_parent->_left == parent)parent_parent->_left = subR;
            else parent_parent->_right = subR;
            subR->_parent = parent_parent;
        }
        subR->_bf = 0;
        parent->_bf = 0;
    }

左右双旋

左右双旋代码实现

    // 左右双旋
    void LRrotate(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;
        RotateL(parent->_left);
        RotateR(parent);
        if (bf == -1)
        {
            subL->_bf = 0;
            parent->_bf = 1;
            subLR->_bf = 0;
        }
        else if (bf == 1)
        {
            subL->_bf = -1;
            parent->_bf = 0;
            subLR->_bf = 0;
        }
        else if (bf == 0)
        {
            subL->_bf = 0;
            parent->_bf = 0;
            subLR->_bf = 0;
        }
        else
        {assert(false);
        }
    }

右左双旋

原理同上。

    // 右左双旋
    void RLrotate(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)
        {
            parent->_bf = 0;
            subR->_bf = 1;
            subRL->_bf = 0;
        }
        else if (bf == 0)
        {
            parent->_bf = 0;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else
        {assert(false);
        }
        
    }

源码地址

gitee 地址:https://gitee.com/BJFyfwl/Lin…

正文完
 0