题目来源:. - 力扣(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; }
};
知识点摘要
- 二叉搜索树的性质:对于树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。
- 删除节点的三种情况:
- 节点没有子节点:直接删除。
- 节点有一个子节点:用子节点替换被删除的节点。
- 节点有两个子节点:找到右子树中的最小节点(或左子树中的最大节点),将其提升到被删除节点的位置,然后递归地删除该最小(或最大)节点。