题目:https://leetcode-cn.com/problems/delete-node-in-a-bst/submissions/
思路一:递归法
分析:
要删掉二叉搜索树中的指定节点,需要找到节点的位置,如果没有找到就返回空,怎么找?如果比根节点大,就遍历右子树;否则就遍历左子树。如果节点的值等于目标值,就找到了要删掉大的节点
要删掉的节点找到后有三种情况:
- 要删掉的节点是叶子节点,直接删掉,返回空
- 要删掉的节点有左孩子或者有孩子,将左孩子或者右 孩子返回
- 要删掉的节点有左孩子和右孩子,将左孩子放在右孩子的左孩子的最左边
步骤:
递归三部曲:
-
函数参数和返回值
函数参数为传入的根节点和目标值,通过递归返回值来将删掉节点的子节点加入二叉搜索树
-
函数终止的条件
节点为空就返回
-
单层逻辑
以下五种情况:
*第一种情况: 没找到删除的节点,遍历到空节点就返回找到删除的节点;
*第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
*第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
*第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
*第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
if (root->val == key) {
// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
if (root->left == nullptr) return root->right;
// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
else if (root->right == nullptr) return root->left;
// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
// 并返回删除节点右孩子为新的根节点。
else {
TreeNode* cur = root->right; // 找右子树最左面的节点
while(cur->left != nullptr) {
cur = cur->left;
}
cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
TreeNode* tmp = root; // 把root节点保存一下,下面来删除
root = root->right; // 返回旧root的右孩子作为新root
delete tmp; // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
return root;
}
}
if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
思路二:迭代法
步骤:
-
写一个函数:deleteone
(1)函数参数为要删掉的目标节点
(2)函数的返回值为目标节点删掉后要连接的节点 ,
(3)函数功能:删掉节点后,找到删掉节点的父节点的 子节点;
(4)流程:如果节点为空;就返回空;如果右节点为空,就将左子树返回。否则就将节点的左子树放在要删掉节点的右节点的左子树的最左面节点上。 -
定义两个节点,一个用于记录要删掉节点,一个用于记录其父节点
-
判断父节点是否为空,为空就是删掉头节点,函数返回deleteone函数的返回值
-
判断父节点的那个子节点要删掉,确定后,将deleteone函数的返回值挂接到父节点的子节点上。
class Solution {
private:
TreeNode*deleteone(TreeNode*target)
{
if(target==NULL)
return NULL;
if(target->right==NULL)
return target->left;
TreeNode*cur=target->right;
while(cur->left)
{
cur=cur->left;
}
cur->left=target->left;
return target->right;
}
public:
TreeNode* deleteNode(TreeNode* root, int key)
{
if(root==NULL)
return root;
TreeNode*cur=root;
TreeNode*pre=NULL;
while(cur)
{
if(cur->val>key)
{
pre=cur;
cur=cur->left;
}
else if(cur->val<key)
{
pre=cur;
cur=cur->right;
}
else
{
break;
}
}
if(pre==NULL)
{
return deleteone(root);//(当时写成return NULL , 当时写的时候没有考虑头节点有子节点,但头节点时要删掉的节点)即使删掉头节点,也是相同的分析过程
}
if(pre->left&&pre->left->val==key)
{
pre->left=deleteone(cur);
}
else if(pre->right&&pre->right->val==key)
{
pre->right=deleteone(cur);
}
return root;
}
};