题目来源:. - 力扣(LeetCode)
题目思路分析
题目要求在给定的二叉搜索树中删除一个具有指定值的节点,并返回删除后的二叉搜索树的根节点。二叉搜索树的性质是,对于树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。这一性质使得我们可以在删除节点时有效地减少搜索空间。
根据节点的子节点数量,删除操作可以分为以下三种情况:
- 节点没有子节点:直接删除该节点,并返回nullptr。
- 节点有一个子节点:返回该节点的子节点,相当于用子节点替换被删除的节点。
- 节点有两个子节点:找到该节点右子树中的最小节点(该节点最多只有一个右子节点),将其提升到被删除节点的位置,然后递归地在右子树中删除该最小节点。
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 如果当前节点为空,直接返回nullptr,表示没有可删除的节点
if(!root){
return root;
}
// 如果要删除的值大于当前节点的值,递归地在左子树中查找并删除节点
if(root->val > key){
root->left = deleteNode(root->left, key);
return root; // 返回当前节点,因为当前节点没有变化
}
// 如果要删除的值小于当前节点的值,递归地在右子树中查找并删除节点
if(root->val < key){
root->right = deleteNode(root->right, key);
return root; // 返回当前节点,因为当前节点没有变化
}
// 如果要删除的值等于当前节点的值,找到需要删除的节点
if(root->val == key){
// 节点没有子节点,直接删除,返回nullptr
if(!root->left && !root->right){
return nullptr;
}
// 节点只有一个左子节点,返回左子节点
if(!root->right){
return root->left;
}
// 节点只有一个右子节点,返回右子节点
if(!root->left){
return root->right;
}
// 节点有两个子节点,找到右子树中的最小节点(即右子树中最左边的节点)
TreeNode* node = root->right;
while(node->left){
node = node->left;
}
// 将找到的最小节点的左子节点接到当前节点的左子树上
// 注意:这里原本的代码缺少了将最小节点的父节点(如果存在)的左子节点更新为nullptr的步骤,
// 但由于我们是通过一直向左遍历找到的最小节点,所以最小节点没有左子节点,
// 因此这一步实际上是不必要的。但为了严谨性,在理解时可以考虑这一点。
node->left = root->left;
// 返回当前节点的右子树(此时最小节点已经替代了当前节点的位置)
return root->right;。
}
// 如果没有找到要删除的节点(理论上不会发生,因为已经通过上面的条件分支处理了所有情况),返回当前节点
return root;
}
};
知识点摘要
- 二叉搜索树的性质:对于树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。
- 删除节点的三种情况:
- 节点没有子节点:直接删除。
- 节点有一个子节点:用子节点替换被删除的节点。
- 节点有两个子节点:找到右子树中的最小节点(或左子树中的最大节点),将其提升到被删除节点的位置,然后递归地删除该最小(或最大)节点。