zoukankan      html  css  js  c++  java
  • 平衡树

    二叉树查找效率很高,但是它有一个缺点。类似下面一棵树,查找效率是线性的:

    定义

    于是,引出了平衡二叉树(Self-balancing binary search tree),也叫 AVLTree

    它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

    使用它,查找效率肯定是 O(log n)。不过,为了保持树的性质,增添和删除节点的时候,需要做额外的旋转操作,这会牺牲掉 O(log n) 的时间

    旋转

    分为4中情况

    1.左左旋转

    5 节点失去了平衡,因为在左子树增加的一个新节点 0,0 在左子树 3 的左孩子上增加的,需要左左旋转,旋转的结果为:

    2. 右右旋转

    9 是在右子树的右子树增加的节点,导致数不平衡,右右旋转:

    3. 左右旋转

    新增的3节点,在左子树的右子树上。需要两次旋转,以2为根,做右右旋转,再以5为根做左左旋转:

    4. 右左旋转,先右旋转,再左旋转。不画图了

    下面是代码,为了方便观察,使用了graphviz画图,需要安装,保存的文件名为:当前目录的tree.png,

    如果没有安装graphviz,注释掉 tree.draw() 

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    
    #include <queue>
    #include <list>
    
    
    template <typename T>
    struct stTreeNode
    {
        T               d;
        int             height;
        stTreeNode<T>  *left;
        stTreeNode<T>  *right;
    
        stTreeNode(T data):d(data),left(NULL),right(NULL) {}
    };
    
    template <typename T>
    class CAVLTree
    {
    public:
        typedef T                           value_type;
        typedef T*                          value_pointer;
        typedef T&                          value_reference;
        typedef const T&                    const_value_reference;
        typedef stTreeNode<T>               node_type;
        typedef node_type*                  node_pointer;
    
    public:
        CAVLTree():root(NULL) {}
        CAVLTree(value_pointer arr, int len);
    
        void    insertData(const_value_reference data) { _insertData(&root, data); }
        void    deleteData(const_value_reference data) { _deleteData(&root, data); }
    
        void    preorderTravel() { _preorderTravel(root); }
        void    inorderTravel() { _inorderTravel(root); }
    
        void    draw();
    
    private:
        node_pointer    root;
    
    private:
        int     getHeight(node_pointer node);
        void    LL(node_pointer *node);
        void    LR(node_pointer *node);
        void    RR(node_pointer *node);
        void    RL(node_pointer *node);
        void    _insertData(node_pointer *node, const_value_reference data);
        void    _deleteData(node_pointer *node, const_value_reference data);
    
        void    _preorderTravel(node_pointer root);
        void    _inorderTravel(node_pointer root);
    };
    
    template <typename T>
    void CAVLTree<T>::_inorderTravel(node_pointer root)
    {
        if (root)
        {
            _inorderTravel(root->left);
            std::cout << root->d << " ";
            _inorderTravel(root->right);
        }
    }
    
    template <typename T>
    void CAVLTree<T>::_preorderTravel(node_pointer root)
    {
        if (root)
        {
            std::cout << root->d << " ";
            _preorderTravel(root->left);
            _preorderTravel(root->right);
        }
    }
    
    template <typename T>
    CAVLTree<T>::CAVLTree(value_pointer arr, int len)
    {
        root = NULL;
    
        for (int i = 0; i < len; ++i)
        {
            _insertData(&root, arr[i]);
        }
    }
    
    template <typename T>
    int CAVLTree<T>::getHeight(node_pointer node)
    {
        return node == NULL ? 0 : node->height;
    }
    
    template <typename T>
    void CAVLTree<T>::LL(node_pointer *node)
    {
        node_pointer q = (*node)->left;
        (*node)->left = q->right;
        q->right = *node;
        (*node)->height = (getHeight((*node)->left) > getHeight((*node)->right) ? getHeight((*node)->left) : getHeight((*node)->right)) + 1;
        q->height = (getHeight(q->left) > getHeight(q->right) ? getHeight(q->left) : getHeight(q->right)) + 1;
        *node = q;
    }
    
    template <typename T>
    void CAVLTree<T>::RR(node_pointer *node)
    {
        node_pointer q = (*node)->right;
        (*node)->right = q->left;
        q->left = *node;
        (*node)->height = (getHeight((*node)->left) > getHeight((*node)->right) ? getHeight((*node)->left) : getHeight((*node)->right)) + 1;
        q->height = (getHeight(q->left) > getHeight(q->right) ? getHeight(q->left) : getHeight(q->right)) + 1;
        *node = q;
    }
    
    template <typename T>
    void CAVLTree<T>::LR(node_pointer *node)
    {
        RR(&(*node)->left);
        LL(node);
    }
    
    template <typename T>
    void CAVLTree<T>::RL(node_pointer *node)
    {
        LL(&(*node)->right);
        RR(node);
    }
    
    template <typename T>
    void CAVLTree<T>::_insertData(node_pointer *node, const_value_reference data)
    {
        if (*node == NULL)
        {
            *node = new node_type(data);
            (*node)->height = 1;
        }
        else if (data < (*node)->d)
        {
            _insertData(&(*node)->left, data);
            if (getHeight((*node)->left) - getHeight((*node)->right) > 1)
            {
                node_pointer left = (*node)->left;
                if (getHeight(left->left) > getHeight(left->right))
                {
                    LL(node);
                }
                else
                {
                    LR(node);
                }
            }
            (*node)->height = (getHeight((*node)->left) > getHeight((*node)->right) ? getHeight((*node)->left) : getHeight((*node)->right)) + 1;
        }
        else
        {
            _insertData(&(*node)->right, data);
            if (getHeight((*node)->right) - getHeight((*node)->left) > 1)
            {
                node_pointer right = (*node)->right;
                if (getHeight(right->right) > getHeight(right->left))
                {
                    RR(node);
                }
                else
                {
                    RL(node);
                }
            }
            (*node)->height = (getHeight((*node)->left) > getHeight((*node)->right) ? getHeight((*node)->left) : getHeight((*node)->right)) + 1;
        }
    }
    
    template <typename T>
    void CAVLTree<T>::_deleteData(node_pointer *node, const_value_reference data)
    {
        if (*node != NULL)
        {
            if (data == (*node)->d)
            {
                // 左子树深度大,把左子树最大值补过来
                if ((*node)->left && getHeight((*node)->left) >= getHeight((*node)->right))
                {
                    node_pointer tmp = (*node)->left;
                    node_pointer parent = (*node)->left;
    
                    while (tmp->right != NULL)
                    {
                        parent = tmp;
                        tmp = tmp->right;
                    }
                    (*node)->d = tmp->d;
                    // (*node)->left是叶子节点
                    if (parent == tmp)
                    {
                        delete (*node)->left;
                        (*node)->left = NULL;
                    }
                    else
                    {
                        parent->right = tmp->left;
                        delete tmp;
                    }
                }
                // 右子树深度大,把右子树最小值补过来
                else if ((*node)->right && getHeight((*node)->left) < getHeight((*node)->right))
                {
                    node_pointer tmp = (*node)->right;
                    node_pointer parent = (*node)->right;
    
                    while (tmp->left != NULL)
                    {
                        parent = tmp;
                        tmp = tmp->left;
                    }
                    (*node)->d = tmp->d;
    
                    if (parent == tmp)
                    {
                        delete (*node)->right;
                        (*node)->right = NULL;
                    }
                    else
                    {
                        parent->left = tmp->right;
                        delete tmp;
                    }
                }
                // 要删除的节点是叶子节点
                else
                {
                    delete *node;
                    *node = NULL;
                }
            }
            else if (data < (*node)->d)
            {
                _deleteData(&(*node)->left, data);
            }
            else
            {
                _deleteData(&(*node)->right, data);
            }
    
            // 调整
            if (*node)
            {
                if (getHeight((*node)->left) - getHeight((*node)->right) > 1)
                {
                    node_pointer left = (*node)->left;
                    if (getHeight(left->left) > getHeight(left->right))
                    {
                        LL(node);
                    }
                    else
                    {
                        LR(node);
                    }
                }
                else if (getHeight((*node)->right) - getHeight((*node)->left) > 1)
                {
                    node_pointer right = (*node)->right;
                    if (getHeight(right->right) > getHeight(right->left))
                    {
                        RR(node);
                    }
                    else
                    {
                        RL(node);
                    }
                }
            }
    
            if (*node)
            {
                (*node)->height = 1 + (getHeight((*node)->left) > getHeight((*node)->right) ?  getHeight((*node)->left) : getHeight((*node)->right));
            }
        }
    }
    
    template <typename T>
    void CAVLTree<T>::draw()
    {
        std::queue<node_pointer, std::list<node_pointer> > Q;
        if (root)
        {
            Q.push(root);
        }
        
        FILE *pf = fopen("avl.dot", "w+");
        if (pf)
        {
            fprintf(pf, "graph btree {
    ");
            fprintf(pf, "	graph [ordering="out"];
    ");
    
            while (!Q.empty())
            {
                node_pointer node = Q.front();
                Q.pop();
                if (node->left)
                {
                    fprintf(pf, "	%d -- %d[color="red"];
    ", node->d, node->left->d);
                    Q.push(node->left);
                }
                if (node->right)
                {
                    fprintf(pf, "	%d -- %d[color="blue"];
    ", node->d, node->right->d);
                    Q.push(node->right);
                }
            }
    
            fprintf(pf, "}
    ");
            fclose(pf);
        }
        system("dot avl.dot -Tpng -o tree.png");
    }
    
    int main()
    {
        int arr[] = {23,5,6,1,3,2,34,67,12,52,82,31,78,95};
        int len = sizeof(arr)/sizeof(int);
    
        CAVLTree<int> tree(arr, len);
        tree.insertData(98);
        tree.insertData(99);
        tree.insertData(10);
    
        tree.deleteData(99);
        tree.deleteData(95);
        tree.deleteData(6);
        // tree.deleteData(2);
        // tree.deleteData(5);
        // tree.deleteData(12);
        // tree.deleteData(78);
        // tree.deleteData(34);
        // tree.deleteData(67);
        // tree.deleteData(98);
        // tree.deleteData(6);
    
        tree.draw();
    
        return 0;
    }
  • 相关阅读:
    Educational Codeforces Round 83 --- F. AND Segments
    Educational Codeforces Round 83 --- G. Autocompletion
    SEERC 2019 A.Max or Min
    2019-2020 ICPC Southwestern European Regional Programming Contest(Gym 102501)
    Educational Codeforces Round 78 --- F. Cards
    今天我学习了一门全新的语言
    codeforces 1323D 题解(数学)
    Educational Codeforces Round 80 (Div. 2) 题解 1288A 1288B 1288C 1288D 1288E
    Educational Codeforces Round 81 (Div. 2) 题解 1295A 1295B 1295C 1295D 1295E 1295F
    Codeforces Round #617 (Div. 3) 题解 1296C 1296D 1296E 1296F
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9919345.html
Copyright © 2011-2022 走看看