AVL树

Posted dalgleish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)\\n", x->bf, x->key,
                avl_max_depth(x),avl_min_depth(x));
        else
            printf("bf=%d, key=%d(%d,%d)\\n", 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

......

 

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

以上是关于AVL树的主要内容,如果未能解决你的问题,请参考以下文章

C++AVL树的实现--详细解析旋转细节

[算法] 数据结构之AVL树

树:AVL树

徒手写的AVL竟然比STL中的红黑树效率更高?✨

AVL树

C++ AVL树