编程语言
首页 > 编程语言> > LeetCode450. 删除二叉搜索树中的节点-迭代与递归解法(含java与c++代码)

LeetCode450. 删除二叉搜索树中的节点-迭代与递归解法(含java与c++代码)

作者:互联网

https://leetcode-cn.com/problems/delete-node-in-a-bst/

题意

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
举例:
在这里插入图片描述

题解

迭代解法

迭代方法通过寻找到待删除节点并记录其父节点,然后根据节点类型进行讨论处理来完成。
在这里插入图片描述

java代码

//删除二叉搜索树的节点 迭代解法
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(null==root)return null;
        //找到待删除节点
        TreeNode node=root;
        TreeNode parent=null;//待删除节点的父节点
        while(node!=null){
            if(key==node.val)break;
            parent=node;//若key存在,则parent一定正确
            if(node.val<key)node=node.right;
            else node=node.left;
        }
        //为空则表示没找到
        if(null==node)return root;
        //此时的node就是待删除节点
        //如果有两个叶子节点,找后继节点,替换值,并指向待删除后驱节点
        if(null!=node.left&&null!=node.right){
            parent=node;
            //找到后继节点
            TreeNode replace =node.right;
            while(replace.left!=null){
                parent=replace;//更新父节点
                replace=replace.left;
            }
            //此时replace就是后继节点,替换值
            node.val=replace.val;
            //指向待删除的后继节点
            node=replace;
        }
        //1.只有一个子节点 2.叶子节点
        TreeNode replace=node.left!=null?node.left:node.right;//获取到子节点
        if(replace==null){//叶子节点
            if(root==node)root=null;//为父节点
            else if(node==parent.left)parent.left=null;//如果删除节点是父节点的左节点
            else parent.right=null;
        }else{//删除节点有一个子节点
            if(root==node){//如果是根节点
                root=replace;//更新根节点
            }else{//用父节点直接连接子节点
                if(node==parent.left)parent.left=replace;
                else parent.right=replace;
            }
        }
        return root;
    }
}

在这里插入图片描述

c++代码

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(!root)return root;
            //找到待删除节点
            TreeNode* node=root;
            TreeNode* parent=NULL;//待删除节点的父节点
            while(node){
                if(key==node->val)break;
                parent=node;//若key存在,则parent一定正确
                if(node->val<key){
                    node=node->right;
                }else if(node->val>key){
                    node=node->left;
                }
            }
            //为空则表示没找到
            if(!node)return root;
            //此时的node就是待删除节点
            //如果有两个叶子节点,找后继节点,替换值,并指向待删除后驱节点
            if(node->left&&node->right){
                parent=node;
                //找到后继节点
                TreeNode* replace =node->right;
                while(replace->left){
                    parent=replace;//更新父节点
                    replace=replace->left;
                }
                //此时replace就是后继节点,替换值
                node->val=replace->val;
                //指向待删除的后继节点
                node=replace;
            }
            //1.只有一个子节点 2.叶子节点
            TreeNode* replace=node->left!=NULL?node->left:node->right;//获取到子节点
            if(!replace){//叶子节点
                if(root==node){//为父节点
                    root=NULL;
                    return root;
                }
                if(node==parent->left){//如果删除节点是父节点的左节点
                    parent->left=NULL;
                }else{
                    parent->right=NULL;
                }
            }else{//删除节点有一个子节点
                if(root==node){//如果是根节点
                    root=replace;//更新根节点
                }else{//用父节点直接连接子节点
                    if(node==parent->left)parent->left=replace;
                    else parent->right=replace;
                }
            }
            return root;
    }
};

递归解法

递归解法中先对函数deleteNode做出定义,删除根节点为root的树中的key节点,并返回新的根节点。如果当前root节点不是key节点且值比key小,则可以对当前root节点的右节点使用deleteNode函数,即删除根节点为root.right的树中的key节点,并返回该树的新头节点,由于右子树的根节点可能发生变化,所以需要对当前节点的右子节点进行更新。若是root的节点的值大于key,则是对左节点进行操作。

 if(root.val>key){//在左边
 	root.left=deleteNode(root.left,key);
 }else if(root.val<key){//在右边
     root.right=deleteNode(root.right,key);
 }

如果当前root节点是待删除的节点则:

  1. 叶子节点:直接删除,即返回null
  2. 有一个子节点的节点:返回它唯一的子节点供其头节连接
  3. 有两个子节点:找到后继节点,替换值,再使用deleteNode方法删除后继节点(后继节点一定没有两个子节点)
//为叶子节点或有一个子节点的节点
 if(root.left==null)return root.right;
 if(root.right==null)return root.left;
 //有两个子节点的节点
 TreeNode successor=findSuccessor(root.right);
 root.val=successor.val;
 root.right=deleteNode(root.right,root.val);

java代码

/**
 * 递归解法
 */
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(null==root)return null;
        if(root.val>key){//在左边
            root.left=deleteNode(root.left,key);
        }else if(root.val<key){//在右边
            root.right=deleteNode(root.right,key);
        }else{//找到了该节点
            //为叶子节点或有一个子节点的节点
            if(root.left==null)return root.right;
            if(root.right==null)return root.left;
            //有两个子节点的节点
            TreeNode successor=findSuccessor(root.right);
            root.val=successor.val;
            root.right=deleteNode(root.right,root.val);
        }
        return root;
    }

    //找到最右侧节点
    private TreeNode findSuccessor(TreeNode node){
        while (node.left != null)
            node=node.left;
        return node;
    }
}

c++代码

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(!root) return root;
        if(key<root->val)root->left=deleteNode(root->left,key);
        if(key>root->val)root->right=deleteNode(root->right,key);
        if(key==root->val){
            if(!root->left&&!root->right)return NULL;
            if(root->left&&!root->right)return root->left;
            if(!root->left&&root->right)return root->right;
            TreeNode* temp=root->right;
            while(temp->left)temp=temp->left;
            root->val=temp->val;
            root->right=deleteNode(root->right,root->val);
        }
        return root;
    }
};

标签:node,right,java,LeetCode450,c++,key,root,节点,left
来源: https://blog.csdn.net/Demon_LMMan/article/details/114300878