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的树:
通过右旋为
从而降低高度为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型
RR型
LR型
RL型
由此看出LL型和RR型对称,LR型和RL型对称。即自平衡时只要做相反的树旋转操作。如LL型做右旋操作达到自平衡,则RR型就做左旋操作达到自平衡。LL型和RR型只要进行一次树旋转就可以达到平衡。而LR型和RL型则要进行2次树旋转才能达到平衡。如下:
LL型(RR型的对称)
右旋
LR型(RL型的对称)
如果只进行1次右旋则
由此得旋转后
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型)
再右旋转
RL型则相反先在右子节点做右旋操作,在进行左旋操作。
5.动画演示工具
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);
}
}
}