判断单旋或双旋的关键是失衡节点的较高子树中更高一侧的方向:LL型为bf(node)>1且bf(node->left)>=0,LR型为bf(node)>1且bf(node->left)<0,RR型为bf(node)<-1且bf(node->right)<=0,RL型为bf(node)<-1且bf(node->right)>0;必须检查子节点高度而非仅凭父节点平衡因子正负决策。

AVL树的左右旋转不是独立操作,而是由失衡节点类型决定的组合动作;直接硬套leftRotate或rightRotate函数大概率导致高度错乱或指针悬空。
怎么判断该用单旋还是双旋?
关键看失衡节点的「较高子树的子树方向」:如果失衡在node->left,且node->left->right更高,就得先对left做leftRotate,再对node做rightRotate(LR型);同理,RR、LL、RL四种情况对应不同组合。不能只看balanceFactor正负就下结论——必须检查子节点的height值。
-
balanceFactor = height(left) - height(right),1 才触发旋转 - LL型:
bf(node) > 1 && bf(node->left) >= 0 - LR型:
bf(node) > 1 && bf(node->left) < 0 - RR型:
bf(node) < -1 && bf(node->right) <= 0 - RL型:
bf(node) < -1 && bf(node->right) > 0
leftRotate和rightRotate必须同步更新高度
旋转后子树高度必然变化,但很多人只改指针不更新height字段,导致后续balanceFactor计算全错。正确顺序是:先算新根高度,再更新旧根高度,且必须用max(height(left), height(right)) + 1,不能沿用旧值。
Node* rightRotate(Node* y) {
Node* x = y->left;
Node* T2 = x->right;
<pre class='brush:php;toolbar:false;'>x->right = y;
y->left = T2;
// 必须先更新 y(原根),再更新 x(新根)
y->height = max(height(y->left), height(y->right)) + 1;
x->height = max(height(x->left), height(x->right)) + 1;
return x;}
立即学习“C++免费学习笔记(深入)”;
插入后递归回溯时,高度更新和旋转的顺序不能颠倒
AVL插入是「自底向上」修复,必须在递归返回途中:先更新当前节点height,再计算balanceFactor,最后决定是否旋转。如果先旋转再更新高度,或者把高度更新放到旋转之后(错误位置),会导致上层节点高度仍为旧值,失衡检测失效。
- 典型错误写法:
insert(...); updateHeight(); rotateIfNecessary();—— 这里updateHeight()没用,因为旋转后子树结构变了,当前节点高度应基于新子树重算 - 正确逻辑:递归插入 → 获取左右子树新高度 →
node->height = max(lh, rh) + 1→ 算bf→ 按类型旋转 → 返回新根 - 旋转函数返回的是新根指针,上层必须用它覆盖原指针,否则树断裂
为什么height字段建议用int而非size_t?
因为balanceFactor是差值,可能为负;若height是无符号类型,height(left) - height(right)在左子树为空时会绕回极大正数(如0 - 1 == 18446744073709551615),直接让所有判断失效。这是调试时最难发现的隐性bug之一。
实际编码中,哪怕你把旋转逻辑全写对了,只要height类型错了,整棵树就在「看似平衡」的状态下持续退化——这种问题不会报错,只会让查找变慢,而且很难定位。


















