题目链接
实现思路
根据二叉查找树的特点(左孩子比当前节点小,右孩子比当前节点大,以当前节点为根节点的二叉树也是二叉查找树),可以分为下面三种情况讨论:
-
当前节点小于 key
继续在左子树中寻找 -
当前节点大于 key
继续在右子树中查找 -
当前节点等于 key
根据题目的意思,会有多种答案,我使用下边的方法:
如果当前节点①既有左孩子,又有右孩子,那么将parent的对应孩子节点设为目标节点的右孩子,并将目标节点的左子树放在目标节点右子树的最左边(根据二叉查找树的定义,左边的节点小于右边,所以需要放到目标节点右子树的最左边)。temp = temp->right; while (temp->left != nullptr) { // 遍历到 以要删除的节点为根节点的 树的最左侧 temp = temp->left; }
如果当前节点②只有右孩子,那么将parent的对应孩子节点设为目标节点的右孩子即可。
如果当前节点③只有左孩子,那么将parent的对应孩子节点设为目标节点的左孩子即可。(①和②的示意图,③的情况类似)示意图如下:
假设需要删除的节点为 4
在实现时,指定parent,指向遍历过程中的父节点,以便在相关节点之间建立联系。
实现代码(C++)
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) { // 空
return nullptr;
}
TreeNode *temp = root, *parent = nullptr;
while (temp != nullptr) {
if (temp->val == key) {
if (temp->left != nullptr && temp->right != nullptr) { // 要删除的节点有左孩子和右孩子
if (temp == root) { // 删除节点为根节点
root = temp->right;
}
if (parent != nullptr) { // 建立联系
if (parent->val > temp->val) {
parent->left = temp->right;
} else {
parent->right = temp->right;
}
}
// 遍历到 以要删除的节点为根节点的 树的最左侧
TreeNode *t = temp->left;
temp = temp->right;
while (temp->left != nullptr) {
temp = temp->left;
}
temp->left = t;
} else if (temp->left == nullptr) {
if (parent != nullptr) {
if (parent->val > temp->val) {
parent->left = temp->right;
} else {
parent->right = temp->right;
}
}
if (temp == root) {
root = temp->right;
}
} else {
if (parent != nullptr) {
if (parent->val > temp->val) {
parent->left = temp->left;
} else {
parent->right = temp->left;
}
}
if (temp == root) {
root = temp->left;
}
}
break;
} else if (temp->val > key) {
parent = temp;
temp = temp->left;
} else {
parent = temp;
temp = temp->right;
}
}
return root;
}
};