给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
1,首先找到需要删除的节点;
2,如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
这道题目是一道二叉搜索树的题目,这个题需要考虑多种情况,因为一旦删除一个节点后影响的可能就是该节点下面的所有节点,非常麻烦,看着就很头大,下面是可能的几种情况:
- 没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点,左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 找到删除的节点,删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 找到删除的节点,删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
这五种情况最复杂的还是第五种,因为要操作的节点数目最多;
其实只要实现了这几点就没有什么难度了;
代码有注释,代码如下:
/**
* 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) {
if (!root) return root;//情况1
if (root->val == key) {
//情况2在情况3,4就概括了
if (!root->left) return root->right;//情况3
else if (!root->right) return root->left;//情况4
else { //情况5
TreeNode* node = root->right;
//遍历到右子树的最左节点
while (node->left) {
node = node->left;
}
//最左节点接上左子树
node->left = root->left;
root = root->right;//删除该节点,即用右子树覆盖
return root;
}
}
if (key < root->val) root->left = deleteNode(root->left, key);
if (key > root->val) root->right = deleteNode(root->right, key);
return root;
}
};