删除二叉搜索树中的节点

力扣题目链接

方法一:递归

   class Solution {  
public:  
    // 定义一个函数,用于删除二叉搜索树中指定键值的节点  
    TreeNode* deleteNode(TreeNode* root, int key) {  
        // 如果根节点为空,直接返回空  
        if (root == nullptr) {  
            return nullptr;  
        }  
  
        // 如果要删除的键值大于当前节点的键值,则在左子树中查找并删除  
        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) {  
            // 如果当前节点没有左右子节点,直接删除当前节点,返回空  
            if (!root->left && !root->right) {  
                return nullptr;  
            }  
  
            // 如果当前节点只有右子节点,直接将右子节点提升到当前节点的位置  
            if (!root->right) {  
                return root->left;  
            }  
  
            // 如果当前节点只有左子节点,直接将左子节点提升到当前节点的位置  
            if (!root->left) {  
                return root->right;  
            }  
  
            // 如果当前节点既有左子节点又有右子节点,找到右子树的最左节点(即右子树的最小值),用它替换当前节点的位置,并调整左右子节点的指针指向  
            TreeNode *successor = root->right;  
            while (successor->left) {  
                successor = successor->left;  
            }  
            root->right = deleteNode(root->right, successor->val);  
            successor->right = root->right;  
            successor->left = root->left;  
            return successor;  
        }  
  
        // 如果以上情况都不满足,则直接返回当前节点,无需进行任何操作  
        return root;  
    }  
};
解题思路关键
  • 找到要删除的节点 我们应该这样思考:既然要删除节点,那么我们首先肯定要找到删除的节点的位置呀。
    如何找到要删除节点的位置呢?
    对!根据二叉搜索树的性质递归寻炸从根节点到要删除节点的路径。
  • 要删除的节点左右都有节点时,如何处理这种情况
            TreeNode *successor = root->right;
            while (successor->left) {
                successor = successor->left;
            }
            root->right = deleteNode(root->right, successor->val);
            successor->right = root->right;
            successor->left = root->left;
            return successor;

或者我们也可以这样写

           TreeNode *successor = root->right;
            while (successor->left) {
                successor = successor->left;
            }
            successor->left=root->left;

            return root->right;

方法二:二级指针解法

      class Solution {
public:
    TreeNode* mergeTree(TreeNode* lt, TreeNode* rt) {
        if (!lt) return rt;
        auto it = lt;
        while (it->right)
            it = it->right;
        it->right = rt;
        return lt;
    }

    TreeNode* deleteNode(TreeNode* root, int key) {
        TreeNode** it = &root;
        while (*it && (*it)->val != key) {
            if (key < (*it)->val)
                it = &(*it)->left;
            else
                it = &(*it)->right;
        }
        if (*it) {
            const auto to_delete = *it;
            *it = mergeTree((*it)->left, (*it)->right);
            delete to_delete;
        }
        return root;
    }
};

也可以这样写

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        TreeNode **p = &root; //指向待删除节点的指针
        while(*p && (*p)->val != key) 
            p = (*p)->val < key ? &(*p)->right : &(*p)->left;
        if(!*p) return root;
        TreeNode **t = &(*p)->right; //指向右树的最左空指针的指针(这里把左树合到右树,反之同理即可)
        while(*t) t = &(*t)->left;
        *t = (*p)->left;
        *p = (*p)->right;
        return root;
    }
};
解题思路关键
  • 二级指针的优点 二级指针就能做到不改变节点内部的的值,即使是空指针也是会有自己的地址,直接通过更换指向子树根节点的指针的地址做到子树的移动
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言二叉搜索树是一种非常常用的数据结构,其插入和查找的时间复杂度都是O(logn)。当然,在使用二叉搜索树时,我们也需要注意它的删除操作,否则会影响它的性能。 二叉搜索树删除操作可以分为以下三种情况: 1. 被删除节点为叶子节点:直接将其删除即可。 2. 被删除节点只有一个子节点:将其子节点替代被删除节点即可。 3. 被删除节点有两个子节点:需要找到其右子树的最小值或左子树的最大值来替代被删除节点。 具体实现时,我们可以使用递归或者迭代的方式进行实现。下面是一个使用递归的实现方式: ``` struct TreeNode* deleteNode(struct TreeNode* root, int key) { if (root == NULL) return root; if (key < root->val) { root->left = deleteNode(root->left, key); } else if (key > root->val) { root->right = deleteNode(root->right, key); } else { if (root->left == NULL) { struct TreeNode* temp = root->right; free(root); return temp; } else if (root->right == NULL) { struct TreeNode* temp = root->left; free(root); return temp; } else { struct TreeNode* temp = findMin(root->right); root->val = temp->val; root->right = deleteNode(root->right, temp->val); } } return root; } struct TreeNode* findMin(struct TreeNode* node) { while (node->left != NULL) node = node->left; return node; } ``` 以上代码,deleteNode函数使用递归实现了删除操作,findMin函数则是用来找到右子树的最小值。在deleteNode函数,我们首先判断了要删除节点是否为空,然后再根据二叉搜索树的性质来判断要删除节点在左子树还是右子树。如果要删除节点为叶子节点或只有一个子节点,则直接将其替换即可;如果要删除节点有两个子节点,则需要找到右子树的最小值(或左子树的最大值),将其赋值给被删除节点,并在右子树删除该最小值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值