平衡因子应在递归回溯中实时更新:每次插入或删除后,先递归处理子树,再更新当前节点height,接着计算bf=height(left)-height(right),最后判断是否失衡并旋转;空节点高度为-1,ll/rr单旋需更新2个节点高度,lr/rl双旋需更新3个节点高度;删除操作需逐层检查并修复多层失衡。

平衡因子怎么实时算才不拖慢插入删除
每次插入或删除后遍历子树算高度,时间复杂度直接升到 O(n),完全失去 BST 的优势。必须在递归回溯过程中顺手更新——节点的 height 只依赖左右子树高度,而平衡因子 bf = height(left) - height(right) 也只需常数时间。
关键点:不要单独写一个 get_height() 递归函数去查;而是让 insert() 和 erase() 的返回值带上当前子树新高度(或直接更新节点 height 成员),边回溯边算 bf。
-
height字段建议存为有符号整数(int),方便后续判断bf == 2 || bf == -2 - 空节点高度设为
-1(不是 0),这样单个叶子节点高度才是 0,和多数教材定义一致,旋转逻辑更不易错 - 更新顺序必须是:先递归处理子树 → 更新当前节点
height→ 计算bf→ 判断是否失衡 → 必要时旋转
四种旋转场景怎么对应 bf 和子树 bf
只看根节点的 bf 不够——比如 bf == 2 可能是 LL 型,也可能是 LR 型,得再看左孩子的 bf。右旋前不检查左子节点的平衡状态,就会把 LR 错当成 LL 处理,树反而更不平衡。
真实判断逻辑(以插入后 bf == 2 为例):
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 若
node->left->bf == 1或0→ LL 型 → 单次右旋(rotate_right()) - 若
node->left->bf == -1→ LR 型 → 先对左孩子左旋(rotate_left(node->left)),再对当前节点右旋 - 同理,
bf == -2时:右孩子bf == -1→ RR;右孩子bf == 1→ RL
注意:bf == 0 也要参与判断(尤其在删除场景中常见),它说明子树等高,此时按 LL/RR 处理是安全的。
旋转后哪些节点的 height 和 bf 必须重算
旋转只是指针交换,不会自动更新高度。漏掉这步,后续所有 bf 都会错。只有参与旋转的两个(或三个)节点需要重算 height,其余不变。
- LL / RR 单旋:仅旋转前后的新根和旧根需更新
height(例如rotate_right()后,原root和新root(即原left)的高度都要重算) - LR / RL 双旋:共三个节点涉及结构变化(如 LR 中的
node、node->left、node->left->right),这三个都得调用update_height() -
update_height(node)就一行:node->height = 1 + std::max(get_height(node->left), get_height(node->right));,其中get_height(nullptr)返回-1
delete 后的平衡修复为什么比 insert 更麻烦
插入最多引发一次失衡(从插入点向上最多一个节点 bf 超限),但删除可能造成多层连续失衡——比如删掉最深叶节点后,从叶子一路往上的祖先都可能从 bf == 0 变成 ±1,再变成 ±2。必须沿递归栈逐层检查并修复。
- 不能在递归中途发现
bf == ±2就 return —— 旋转后子树高度可能变,上面的祖先bf还得重新算 - 典型错误:
erase()返回的是更新后的子树根,但没同步更新父节点对其的指针(尤其双旋后新根不是原node,父节点的left/right指针必须重赋值) - 建议统一用返回值传递新子树根(即使没旋转也要 return 当前 node),避免隐式指针失效
真正麻烦的不是旋转逻辑本身,而是 delete 后高度变化的传播方向和时机——它不像 insert 那样单向可预测,必须老老实实每层都 update_height + check_bf + rotate。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










