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;
    }
  • 相关阅读:
    iOS MDM证书制作
    iOS 跳转到设置界面
    创建自己的远程私有库
    制作属于自己的cocoapod仓库和spec
    iOS 推送通知证书制作
    自定义导航栏之滑动返回
    xcode使用xib创建cell ,出现崩溃问题
    Xcode使用xib拖线时出现: could not insert new outlet connection
    2014年糯米网校招测试工程师题目解析
    JAVA操作LDAP的详解(JLDAP)
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9919345.html
Copyright © 2011-2022 走看看