必须用双旋转而非单旋转的条件是:失衡节点的较高子树朝相反方向倾斜,如lr型(node左高且node->left右高)或rl型(node右高且node->right左高),此时单旋无法修正平衡因子。

双旋转不是“先左再右”或“先右再左”的机械拼接,而是针对特定失衡形态(LL/RR 的反向嵌套)必须原子化执行的一组指针重连操作;漏掉任一子树挂载步骤,树就直接断裂。
什么时候必须用双旋转而不是单旋转?
当插入/删除导致节点失衡,且其较高子树的“高侧子节点”本身朝相反方向倾斜时,单旋转无法恢复平衡因子。典型场景:
-
node的左子树高,但node->left的右子树更高(即 LR 型)→ 必须left-right双旋 -
node的右子树高,但node->right的左子树更高(即 RL 型)→ 必须right-left双旋
错误判断会导致旋转后 balance factor 仍为 ±2,甚至出现负高度。
left-right 双旋的四步指针重连顺序不能乱
以 LR 失衡为例,设 A 为失衡节点,B = A->left,C = B->right。正确顺序是:
- 先将
C->left挂到B->right(保全 C 左子树) - 再将
B作为C->left - 再将
C->right挂到A->left(保全 C 右子树) - 最后将
C替换A成为新根
若跳过第 1 步直接动 B->right,C->left 子树就永久丢失;若第 3 步写成 A->right = C->right,则右子树被错误覆盖。
旋转后 balance factor 的重算逻辑依赖子树高度变化
双旋不改变整棵树节点数,但会局部重分布高度。重算必须基于实际子树高度,而非简单赋值:
-
update_balance(A)→ 实际调用height(A->left) - height(A->right) -
update_balance(B)→ 同理,不能假设为 0 或 ±1 -
update_balance(C)→ 它成为新父节点,其 BF =height(C->left) - height(C->right),而这两个子树刚被重新挂载,必须真实计算
很多实现用“经验公式”如 C->bf = 0; B->bf = -C->bf;,这仅在插入场景且无重复高度更新时侥幸成立;一旦涉及删除或连续旋转,必出错。
AVL 删除触发双旋转时,必须在回溯路径上逐层检查并修复
插入只需处理首个失衡点,但删除可能使多个祖先同时失衡。常见错误是:在某层做完 right-left 旋后,直接返回,忽略上层节点的 balance factor 已因子树高度变化而越界。
- 每次旋转后,必须继续向上更新 parent 的高度和 BF
- 若 parent 新 BF = ±2,且其子树结构匹配 RL/LR,则立即再次双旋
- 不能把“是否需旋转”判断放在递归入口,而要放在旋转完成、高度更新之后
最易忽略的是:双旋转本身不保证父节点平衡——它只解决当前节点,其余交由回溯逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











