删除BST节点不能只delete后返回,因父节点指针会悬空导致崩溃;AVL旋转后必须重算高度以防失衡误判;一次旋转常不够,需自底向上逐层rebalance;unique_ptr可简化内存管理但需适配移动语义。

删除BST节点时,为什么不能只用delete后直接返回?
因为删除后父节点的指针可能悬空,或子树结构断裂。C++中必须显式更新父节点对应的孩子指针(left或right),否则后续遍历、查找会崩溃或逻辑错乱。
常见错误现象:Segmentation fault、查不到刚删掉的相邻值、中序遍历结果重复或缺失。
- 若被删节点是叶子,需将其父节点的
left或right置为nullptr - 若被删节点只有左/右子树,父节点应“绕过”它,直接连到该子树根
- 若被删节点有两个子节点,需用中序后继(右子树最左)替换,并递归删除该后继——此时仍要更新其父节点指针
AVL平衡恢复:旋转后为什么必须重新计算高度?
AVL树靠height差判断是否失衡,而单次左旋/右旋会改变3个节点(原根、新根、孙子)的高度值。不重算会导致后续插入/删除误判平衡状态,最终退化成链表。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 每次旋转后,按顺序调用
updateHeight()更新新根和原根(例如右旋后,先更新newRoot,再更新oldRoot) - 高度定义统一为:
height = 1 + max(left ? left->height : -1, right ? right->height : -1)(空节点高度为-1更易处理边界) - 不要在旋转函数内硬编码高度赋值,封装
updateHeight(node)并复用
删除触发的双层失衡:为什么一次旋转往往不够?
BST删除可能让某祖先节点的平衡因子从±1变为±2,但它的孩子节点也可能同步失衡——尤其当删除的是高权重子树的叶子时。AVL要求从被删节点向上逐层检查,每遇到失衡点都必须旋转+更新高度,且旋转后要继续向上检查(因为旋转可能改变更高层的高度)。
典型场景:删除右子树最深叶子,导致根节点左子树比右子树高2,但左子节点本身又因右倾需先做LR旋转。
- 必须用递归或栈回溯方式,在删除返回路径上逐层调用
rebalance() -
rebalance()内部先更新当前节点高度,再根据getBalanceFactor()决定旋转类型(LL/LR/RR/RL) - 旋转函数返回新子树根,上层必须用该返回值更新自己的
left或right指针
C++实现中std::unique_ptr能简化内存管理吗?
能,但要注意所有权语义变化。用std::unique_ptr<node></node>替代裸指针后,所有赋值、传参、返回都变成移动语义,delete自动发生;但旋转和删除逻辑需改写为转移std::move()所有权,而非交换指针地址。
容易踩的坑:
- 不能对
unique_ptr做node->left = node->right.release()这类裸指针操作,应改用std::move() - 递归删除函数签名得是
void remove(std::unique_ptr<node>& root, int key)</node>,通过引用传递才能修改原指针 - 旋转函数返回
std::unique_ptr<node></node>,上层接收时必须用std::move()赋值,否则编译失败
裸指针版本更贴近底层理解,unique_ptr版本更安全——但两者在平衡逻辑、旋转条件、高度更新这些关键路径上完全一致。
真正难的不是写旋转代码,而是想清楚:哪一层需要更新高度、哪个指针必须被重连、旋转后谁成了新子树根。这些地方一错,整棵树就 quietly 崩溃了。


















