AVL树的平衡因子定义为左子树高度减右子树高度,取值限于-1、0、1;实际实现中不显式存储该因子,而是通过节点缓存的height字段实时计算,插入删除时需自底向上维护高度并及时旋转以保持平衡。

二叉搜索树节点如何定义平衡因子
平衡因子是 AVL 树的核心指标,定义为左子树高度减右子树高度,必须是 -1、0 或 1。它不是额外存储的“属性”,而是依赖于子树高度动态计算的值——所以关键不是“存因子”,而是“高效算高度”。如果每次调用都递归求高,时间开销会退化到 O(n),破坏 AVL 的 O(log n) 优势。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 在节点结构中直接缓存
height字段(而非只存balance),更新时自底向上维护; - 高度初始化为
1(单节点树高为 1),空指针高度视为0; - 平衡因子不单独存,用
getBalance(node)函数实时计算:node ? node->left_height - node->right_height : 0; - 避免在插入/删除中途反复调用高度函数——所有旋转前先更新涉及节点的高度。
LL、RR、LR、RL 四种旋转怎么写才不出错
旋转本质是局部指针重连,错误常源于:搞反父子关系、漏更新高度、旋转后没重连父节点指针。比如 LL 旋转不是“把左孩子提上来”就完事,而是要让原根节点变成新根的右孩子,并接管其右子树。
实操建议:
立即学习“C++免费学习笔记(深入)”;
-
LL旋转:设node失衡,newRoot = node->left;令node->left = newRoot->right,再令newRoot->right = node; -
LR先对node->left做RR,再对node做LL——注意两次旋转后,node->left已变,不能复用旧指针; - 所有旋转函数返回新根节点(便于上层重连),例如:
Node* rotateLL(Node* node); - 旋转后必须立即更新两个受影响节点的高度(顺序:先子后父),否则后续
getBalance()计算错误。
插入后如何触发并执行自平衡
AVL 插入不是插完再统一检查,而是在递归回溯路径上逐层检查平衡因子。一旦某节点失衡(abs(getBalance(node)) > 1),立刻在其子树内完成旋转,并将旋转后的新根返回给父节点——这步漏掉就会导致树断裂。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 插入函数必须返回当前子树的新根(即使没旋转也要返回原
node),上层用该返回值更新自己的左/右指针; - 检查平衡的时机是:插入递归返回后、更新当前节点高度之前;
- 失衡判断用
if (getBalance(node) > 1)判断左偏,再结合getBalance(node->left)决定是LL还是LR;右偏同理; - 不要在旋转前修改
node的左右指针——先确定类型、再调用对应旋转函数、再用返回值赋值。
删除节点后为什么更难平衡,该怎么处理
删除比插入复杂:它可能在任意位置发生,且删完后高度变化路径更长,一次删除可能触发多层旋转(而插入最多一次)。更隐蔽的问题是:若用“前驱/后继替换法”删除,替换节点本身可能带失衡,需从该节点开始向上回溯检查。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 删除后,必须从被删节点的父节点开始,沿路径向上直到根,逐个更新高度并检查平衡;
- 若某节点失衡,旋转后得到新根,需继续用该新根作为下一个父节点的子节点(即:旋转返回值要赋给上层指针);
- 避免在删除函数里直接调用
rotateXX后就返回——必须确保整条回溯路径上的高度和连接都一致; - 调试时打印每个节点的
height和getBalance(),比只看结构更容易定位哪一层旋转没生效。
真正容易被忽略的是高度更新的顺序和旋转后的指针归属——哪怕逻辑全对,一个 node->left = rotateLL(node->left) 写成 rotateLL(node->left) 而没赋值,整棵树就断开了。

















