目录
- 二叉搜索树(BST)快速回顾
- 《双截棍》分拣算法:灵感与定义
- BST节点删除的难点与分类
- C++实现BST节点删除代码详解
- 优化技巧:递归与非递归思路
- 进阶Boss战:双指针与旋转操作(选讲)
- 总结与实战建议
1️⃣ 二叉搜索树(BST)快速回顾
- 定义:二叉搜索树是一种有序二叉树,满足:左子树所有节点值 < 根节点值 < 右子树所有节点值。
- 性质:查找、插入、删除平均时间复杂度均为 O(log n)。
- 用途:高效分拣、动态集合管理。
2️⃣ 《双截棍》分拣算法:灵感与定义
- 灵感来源于双截棍灵活且快速的切割动作。
- 在BST中,“双截棍”指的是用左右两把“棍子”协同操作,快速定位并“分拣”节点。
- 主要应用在节点删除操作中,通过灵活调整左右子树,实现快速节点替换和树结构调整。
3️⃣ BST节点删除的难点与分类
删除节点时,主要有三种情况:
情况 | 说明 | 处理方法 |
---|---|---|
叶子节点 | 直接删除,不影响其他节点 | 直接删除节点指针 |
仅有一个子节点 | 用子节点替代被删除节点 | 直接连接子节点到父节点 |
有两个子节点 | 需找到替代节点(前驱或后继)替换节点值,再删除替代节点 | 找到中序前驱或后继节点替换,然后删除它 |
节点删除的“Boss战”主要是第三种情况,处理不当会破坏BST性质。
4️⃣ C++实现BST节点删除代码详解
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class BST {
public:
TreeNode* root;
BST() : root(nullptr) {}
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
if (key < root->val) {
root->left = deleteNode(root->left, key);
} else if (key > root->val) {
root->right = deleteNode(root->right, key);
} else {
// 找到了要删除的节点
// 情况1和2
if (!root->left) {
TreeNode* rightChild = root->right;
delete root;
return rightChild;
} else if (!root->right) {
TreeNode* leftChild = root->left;
delete root;
return leftChild;
}
// 情况3:两个子节点,找到后继节点替换
TreeNode* successor = getMin(root->right);
root->val = successor->val;
root->right = deleteNode(root->right, successor->val);
}
return root;
}
private:
TreeNode* getMin(TreeNode* node) {
while (node && node->left) {
node = node->left;
}
return node;
}
};
代码说明:
- 递归查找待删除节点。
- 叶子或单子节点直接删除或替换。
- 双子节点则用右子树最小节点(后继)替换,再删除后继节点。
- 保证BST结构不被破坏。
5️⃣ 优化技巧:递归与非递归思路
- 递归简洁易懂,适合快速实现。
- 非递归实现更节省栈空间,适合对性能有要求的场景。
- 结合父节点指针可简化删除和替换过程。
6️⃣ 进阶Boss战:双指针与旋转操作(选讲)
- 有时结合双指针技巧快速找到目标节点和其父节点,简化操作。
- 在自平衡树(AVL/红黑树)中,节点删除后需旋转调整,维持树平衡。
- 《双截棍》分拣理念在旋转中同样适用,双方向协作调整,快速恢复结构。
7️⃣ 总结与实战建议
- 节点删除是BST中最复杂的操作,要牢牢记住三种情况。
- 理解中序前驱后继替换策略,是暴打节点删除Boss的关键。
- 多练递归和非递归版本,加深对树结构指针操作的熟悉。
- 掌握后续自平衡树的旋转技巧,打造更强的“分拣技能”。
发表回复