zoukankan      html  css  js  c++  java
  • AVL树

    算法原理请参考《算法导论》,简单描述下:就是所有节点(根节点除外)的最大深度和最小深度之间的差小于2。

    代码实现,只贴出和红黑树不同的类成员函数实现,其余都是和红黑树一样。

    类声明

    template <typename T>
    class avl_tree {
    public:
        typedef struct _avl_type {
            _avl_type(_avl_type *_left, _avl_type *_right, _avl_type *_p, int _bf, T k) :
                left(_left), right(_right), p(_p), bf(_bf), key(k) {}
            int bf;//当前结点左右子树的高度差
            T key;
            _avl_type *left, *right, *p;
        }avl_type, *pavl_type;
        avl_tree(T *A, int n):root(NULL) {
            for (int i = 0; i < n; i++)
                avl_insert(A[i]);
        }
        ~avl_tree() {
            avl_empty(root);
        }
        void left_rotate(pavl_type x);
        void right_rotate(pavl_type x);
        pavl_type avl_max(pavl_type x);
        pavl_type avl_min(pavl_type x);
        pavl_type avl_search(T key);
        pavl_type avl_next(T key);//后趋
        pavl_type avl_prev(T key);//前继
        void avl_insert(T key);
        void avl_delete(T key);
        void avl_show(pavl_type x);
        pavl_type avl_root();
        void avl_empty(pavl_type x);
    private:
        int avl_max_depth(pavl_type x);
        int avl_min_depth(pavl_type x);
        void avl_fixup(pavl_type x);//后续修复
        pavl_type root;
    };

    和红黑树不同的类成员函数实现

    avl_insert成员函数

    template <typename T>
    void avl_tree<T>::avl_insert(T key) {
        pavl_type y = NULL, x = root, z = new avl_type(NULL, NULL, NULL, 0, key);
        while (x != NULL) {
            y = x;
            if (key < x->key)
                x = x->left;
            else
                x = x->right;
        }
        z->p = y;
        if (y == NULL)
            root = z;
        else {
            if (key < y->key)
                y->left = z;
            else
                y->right = z;
        }
        avl_fixup(root);//插入和删除统一使用一个修复函数,和红黑树不同
    }

    avl_delete成员函数

    template <typename T>
    void avl_tree<T>::avl_delete(T key) {
        pavl_type z = avl_search(key), y, x;
        if (z == NULL) return;
        if (z->left == NULL || z->right == NULL)//y是待删除的节点
            y = z;//z有一个子节点
        else
            y = avl_next(key);//z有两个子节点,后继和前趋保证了y有一个或没有子节点
        if (y->left != NULL)
            x = y->left;
        else
            x = y->right;
        if (x != NULL) //存在一个子节点,先更正父子关系
            x->p = y->p;
        if (y->p == NULL)//再决定是在左或者右节点
            root = x;
        else {
            if (y->p->left == y)
                y->p->left = x;
            else
                y->p->right = x;
        }
        if (y != z)//处理两个子节点的交换
            z->key = y->key;
        avl_fixup(root);
        delete y;
    }

    avl_fixup成员函数,修复节点

    template <typename T>
    void avl_tree<T>::avl_fixup(typename avl_tree<T>::pavl_type x) {
        if (x != NULL) {
            avl_fixup(x->left);
            avl_fixup(x->right);//采用后续修复节点
            x->bf = avl_max_depth(x) - avl_min_depth(x);//自动更新
            if (x->bf == 2) {//不平衡
                if (avl_max_depth(x->right) > avl_max_depth(x->left)) {//右子树大
                    if (x->right->right) //右子树插入右孩子
                        left_rotate(x);
                    else if (x->right->left && !x->right->right) {//右子树插入左孩子
                        right_rotate(x->right);
                        left_rotate(x);
                    }
                }
                else {
                    if (x->left->left)//左子树插入左孩子
                        right_rotate(x);
                    else if (x->left->right && !x->left->left) {//左子树插入右孩子
                        left_rotate(x->left);
                        right_rotate(x);
                    }
                }
                x = x->p;
                if (x) x->bf = avl_max_depth(x) - avl_min_depth(x);
                if (x && x->left) x->left->bf = avl_max_depth(x->left) - avl_min_depth(x->left);
                if (x && x->right) x->right->bf = avl_max_depth(x->right) - avl_min_depth(x->right);
            }
        }
    }

    avl_max_depth成员函数,最大深度

    template <typename T>
    int avl_tree<T>::avl_max_depth(typename avl_tree<T>::pavl_type x) {
        if (x == NULL)
            return 0;
        int l = avl_max_depth(x->left);
        int r = avl_max_depth(x->right);
        return (l > r ? l : r) + 1;
    }

    avl_min_depth成员函数,最小深度

    template <typename T>
    int avl_tree<T>::avl_min_depth(typename avl_tree<T>::pavl_type x) {
        if (x == NULL) 
            return 0;
        int l = avl_min_depth(x->left);
        int r = avl_min_depth(x->right);    
        return (l < r ? l : r) + 1;
    }

    avl_show成员函数,打印AVL树信息,保证函数都正确

    template <typename T>
    void avl_tree<T>::avl_show(typename avl_tree<T>::pavl_type x) {
        if (x != NULL) {
            avl_show(x->left);
            if (x==root) 
                printf("[root]bf=%d, key=%d(%d,%d)
    ", x->bf, x->key,
                    avl_max_depth(x),avl_min_depth(x));
            else
                printf("bf=%d, key=%d(%d,%d)
    ", x->bf, x->key,
                    avl_max_depth(x),avl_min_depth(x));
            avl_show(x->right);
        }
    }

    之前的修复成员函数,效率太低,给一个效率特别高的修复函数

    插入后修复调用:avl_fixup_1(z);

    删除后修复调用:avl_fixup_1(y->p);

    template <typename T>
    void avl_tree<T>::avl_fixup_1(typename avl_tree<T>::pavl_type x) {
        while (x) {
            x->bf = avl_max_depth(x) - avl_min_depth(x);//自动更新
            if (x->left) x->left->bf = avl_max_depth(x->left) - avl_min_depth(x->left);
            if (x->right) x->right->bf = avl_max_depth(x->right) - avl_min_depth(x->right);
            if (x != root && x->bf == 2) {//不平衡
                if (avl_max_depth(x->right) > avl_max_depth(x->left)) {//右子树大
                    if (x->right->right) //右子树插入右孩子
                        left_rotate(x);
                    else if (x->right->left && !x->right->right) {//右子树插入左孩子
                        right_rotate(x->right);
                        left_rotate(x);
                    }
                }
                else {
                    if (x->left->left)//左子树插入左孩子
                        right_rotate(x);
                    else if (x->left->right && !x->left->left) {//左子树插入右孩子
                        left_rotate(x->left);
                        right_rotate(x);
                    }
                }
            }
            x = x->p;
        }
    }

    数据测试

     输入数据:5 3 7 2 4 6 8 0 1 -1q

    结果显示

    其余数据,可以自己测试

    5 6 -1 0 -6 -8 99 6q
    12 8 18 5 11 17 4 2q
    5 2 0 -6 -99 -5 5 1q

    ......

    所有代码均经过测试,结果正确!

  • 相关阅读:
    集训第四周(高效算法设计)P题 (构造题)
    集训第四周(高效算法设计)O题 (构造题)
    集训第四周(高效算法设计)N题 (二分查找优化题)
    集训第四周(高效算法设计)M题 (扫描法)
    集训第四周(高效算法设计)L题 (背包贪心)
    集训第四周(高效算法设计)K题 (滑窗问题)
    集训第四周(高效算法设计)J题 (中途相遇法)
    集训第四周(高效算法设计)I题 (贪心)
    UVA302 John's trip(欧拉回路)
    P4281 [AHOI2008]紧急集合 / 聚会
  • 原文地址:https://www.cnblogs.com/dalgleish/p/9029037.html
Copyright © 2011-2022 走看看