【数据结构】AVL树的基础

1.简介

AVL树 是在二叉查找树的基础上附加自平衡特性。AVL树规定在任意节点的左右两个子树的高度最多相差1。 如果高度相差超过1,则进行自平衡。

2.定义

在一个二叉查找树内任意节点 x x x平衡因子 B F ( x ) BF{\left(x\right)} BF(x)为该节点左右子节点的高低差。当所有节点都满足的 B F ( x ) ∈ { − 1 , 0 , 1 } BF{\left(x \right)}\in{\left\{-1,0,1 \right\}} BF(x){1,0,1}时,这个二叉树就为AVL树。

3.实现原理

树旋转 可以在不影响元素顺序的情况下,通过改变树的形状来上移或下移节点从而调整树的高度。举例一个高度为2的树:

30
20
NULL
10
NULL

通过右旋为

20
10
30

从而降低高度为1。
在此基础上,每次添加或删除节点。就遍历受影响的节点,如果平衡因子 B F ( x ) ∈ { − 2 , 2 } BF{\left(x\right)}\in{\left\{-2,2\right\}} BF(x){2,2}就通过树旋转调整树的高度以此来达到平衡。

4.需要平衡的情况

因为当 B F ( x ) ∈ { − 2 , 2 } BF{\left(x\right)}\in{\left\{-2,2\right\}} BF(x){2,2}就需要进行自平衡操作,而当平衡因子为2或-2是会有四种情况如下:
LL型

30
20
b
10
a

RR型

10
a
20
b
30

LR型

30
10
d
a
20
b
c

RL型

30
a
20
10
d
b
c

由此看出LL型和RR型对称,LR型和RL型对称。即自平衡时只要做相反的树旋转操作。如LL型做右旋操作达到自平衡,则RR型就做左旋操作达到自平衡。LL型和RR型只要进行一次树旋转就可以达到平衡。而LR型和RL型则要进行2次树旋转才能达到平衡。如下:

LL型(RR型的对称)

30
20
d
10
c
a
b

右旋

20
10
30
c
d
a
b

LR型(RL型的对称)

30
10
d
a
20
b
c

如果只进行1次右旋则

10
a
30
20
d
b
c

由此得旋转后 B F ( x ) BF{\left(x\right)} BF(x)还是等于2或-2。(至于2还是-2则由 B F ( x ) BF{\left(x\right)} BF(x)是左子节点高度减右子节点高度,还是右子节点高度减左子节点高度。)因此,LR型要进行2次树旋转操作。如下:
先在左子节点进行左旋转(变为LL型)

30
20
d
10
c
a
b

再右旋转

20
10
30
a
b
c
d

RL型则相反先在右子节点做右旋操作,在进行左旋操作。

5.动画演示工具

AVL树在线可视化网站

6.C语言代码片段

用递归获取深度以此来计算平衡因子

int maxDepthByNode(Node* node) {
    int left_depth = 0;
    int right_depth = 0;

    if (leftNodeIsExists(node)) {
        left_depth += 1;
        left_depth += maxDepthByNode(node->left_node);
    }

    if (rightNodeIsExists(node)) {
        right_depth += 1;
        right_depth += maxDepthByNode(node->right_node);
    }

    return (left_depth >= right_depth) ? left_depth : right_depth;
}

int getBalanceFactor(Node* node) {
    int left_depth = 0;
    int right_depth = 0;

    if (leftNodeIsExists(node)) {
        left_depth += 1;
        left_depth += maxDepthByNode(node->left_node);
    }

    if (rightNodeIsExists(node)) {
        right_depth += 1;
        right_depth += maxDepthByNode(node->right_node);
    }

    return left_depth - right_depth;
}

因为我编码时平衡因子计算是左子节点高度减去右子节点高度。由此平衡因子>1为 LL型或LR型

void nodeRebalance(BinaryTree* tree, Node* node) {
    int factor = getBalanceFactor(node);
    int sub_factor = 0;

    if (factor > 1) {
        sub_factor = getBalanceFactor(node->left_node);
        if (sub_factor > 0) { // LL型
            rotateRightByNode(tree, node);
        }
        if (sub_factor < 0) { // LR型
            rotateLeftByNode(tree, node->left_node);
            rotateRightByNode(tree, node);
        }
    }

    if (factor < -1) {
        sub_factor = getBalanceFactor(node->right_node);
        if (sub_factor > 0) { // RL型
            rotateRightByNode(tree, node->right_node);
            rotateLeftByNode(tree, node);
        }
        if (sub_factor < 0) { // RR型
            rotateLeftByNode(tree, node);
        }
    }
}

参考

  1. AVL tree - Wikipedia
  2. 详解AVL树(基础篇)- 知乎@Name1e5s
  • 37
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值