AVL树左旋触发条件是节点BF=-2且右子节点BF=-1(RR型),右旋是BF=2且左子节点BF=1(LL型);LR/RL型需先对子节点反向旋转再对当前节点同向旋转。

AVL树左旋和右旋的触发条件是什么
左旋(rotateLeft)发生在右子树过高,且失衡节点的右子节点的右子树更重(RR型);右旋(rotateRight)发生在左子树过高,且失衡节点的左子节点的左子树更重(LL型)。关键不是“高度差=2”就立刻旋转,而是要结合**平衡因子(BF = height(left) - height(right))**判断:当某节点bf == -2且其右子节点bf == -1时,才做左旋;bf == 2且其左子节点bf == 1时,才做右旋。
容易忽略的是:LL/RR只是基础情形,还有LR/RL型——这时不能直接单旋,必须先对子节点做一次反向旋转,再对当前节点同向旋转。比如LR型:先对左子节点rotateLeft,再对当前节点rotateRight。
左右旋代码里最容易写错的指针更新顺序
旋转本质是局部子树结构重连,核心是三步:暂存关键子节点 → 更新父指针 → 修正高度。常见错误是顺序颠倒导致指针悬空或循环引用。
-
rotateRight中,必须先保存node->left->right(即B的右子树),再把node->left提到根位置,最后把原node挂到新根的右子树上 - 更新
height必须在子树结构稳定后进行,否则getHeight(node->left)可能读到未同步的高度值 - 如果用递归方式维护高度,务必在旋转后立即调用
updateHeight(node)和updateHeight(newRoot),顺序不能反
Node* rotateRight(Node* node) {
Node* newRoot = node->left;
Node* temp = newRoot->right; // 先存B的右子树
newRoot->right = node; // B的右指针指向A
node->left = temp; // A的左指针指向temp
updateHeight(node); // 先更新子节点高度
updateHeight(newRoot); // 再更新新根高度
return newRoot;
}
为什么插入后要从下往上回溯检查并旋转
AVL插入是递归向下找位置,但平衡修复必须自底向上——因为只有插入路径上的节点才可能失衡,且高层节点的平衡因子依赖于子树高度,必须等子树旋转完成、高度更新后才能重新计算。
立即学习“C++免费学习笔记(深入)”;
典型错误是“一发现bf == 2就立刻旋完返回”,这会中断回溯,导致祖先节点高度没更新、BF计算错误,后续可能漏修复或误修复。
- 每次递归返回时,都要调用
updateHeight和getBalanceFactor - 根据当前节点BF值决定是否旋转,并把旋转后的子树根作为返回值传给上层
- 单旋后该节点平衡,但上层仍可能失衡,所以不能提前return,必须继续回溯
insert函数里如何统一处理四种失衡类型
不建议用一堆if-else硬编码判断LL/LR/RR/RL——逻辑易错且难维护。推荐先算出当前节点BF和左右子节点BF,再用组合判断:
- 若
bf == 2 && getBalanceFactor(node->left) >= 0→ LL型 →rotateRight - 若
bf == 2 && getBalanceFactor(node->left) < 0→ LR型 → 先rotateLeft(node->left),再rotateRight(node) - 若
bf == -2 && getBalanceFactor(node->right) <= 0→ RR型 →rotateLeft - 若
bf == -2 && getBalanceFactor(node->right) > 0→ RL型 → 先rotateRight(node->right),再rotateLeft(node)
注意>= 0和<= 0的边界处理:LL/RR要求子节点BF同号,而LR/RL要求异号;用>=而非== 1能兼容插入后子节点BF为0的情况(即刚插入叶节点,子树尚平衡)。
高度更新和BF计算看似简单,但一旦和递归插入、多层旋转耦合,就很容易在某个回溯层级漏掉updateHeight,或者在LR/RL型中忘了把第一次旋转的结果赋回给node->left或node->right。这些细节不报错,但会导致树逐渐退化成链表。


















