LeetCode 删除二叉搜索树中的节点(450题)递归与非递归

LeetCode 删除二叉搜索树中的节点

@author:Jingdai
@date:2020.12.06

题目描述(450题)

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

题目分析

对于一个二叉搜索树,要删除树中一个节点,分3种情况。

情况1:如果要删除的节点是叶子节点,比如图中节点12,可以直接删除。

在这里插入图片描述

情况2:如果要删除的节点只有一个子树,比如图中节点5,可以将该节点的子树提上去就行。

在这里插入图片描述

情况3:如果要删除的节点有两个孩子,比如图中节点15。对于这种情况,为了使搜索二叉树的结构不被破坏,需要从删除节点的右子树中找到最小的节点,将这个节点的值赋给删除节点,然后再删除右子树中最小的节点。(当然从删除节点的左子树中找最大的节点也行)

在这里插入图片描述

思路及代码

有两种方式实现,一种是递归,一种是非递归。

递归方法

我们先看函数的定义,删除一个节点,并返回二叉搜索树(有可能被更新)的根节点的引用。

key 的值比当前节点的值大,说明应该去右子树中删除,将右子树删除 key 后的根节点返回,并将结果赋值给当前节点的右子树。即: root.right = deleteNode(root.right, key);

key 的值比当前节点的值小,说明应该去左子树中删除,将左子树删除 key 后的根节点返回,并将结果赋值给当前节点的左子树。即: root.left = deleteNode(root.left, key);

key 的值和当前节点的值相等,说明应该删除了,就按照题目分析中的三种情况进行删除。

完整的代码如下。

public TreeNode deleteNode(TreeNode root, int key) {
    
    
    if (root == null)
        return null;

    if (key == root.val) {
    
    
        // 1.leaf
        if (root.left == null && root.right == null) {
    
    
            return null;
        } else if (root.left == null) {
    
     // 2.left is null
            return root.right;  
        } else if (root.right == null) {
    
     // 3.right is null
            return root.left;
        } else {
    
     // 4.left/right r not null
            TreeNode rightTreeMin = root.right;
            while (rightTreeMin.left != null) {
    
    
                rightTreeMin = rightTreeMin.left;
            }
            root.val = rightTreeMin.val;
            root.right = deleteNode(root.right, rightTreeMin.val);
        }
    } else if (key > root.val) {
    
    
        root.right = deleteNode(root.right, key);
    } else {
    
    
        root.left = deleteNode(root.left, key);
    }
    return root;
}

非递归方法

思路还是类似,当 key 的值比当前节点的值大时,就去右子树中查找;当 key 的值比当前节点值小时,就去左子树中查找,直到找到要删除的节点。但是注意非递归方法中还需要记录当前节点的父节点,用于最后的删除,因为递归方法是在递归函数的上一层进行处理的,所以不用记录。当删除节点的左右子树都不为空时,父节点有两种情况。如图左,当要删除节点20时,右子树最小的节点就是 cur 的右孩子,pre 等于 cur,此时删除右子树最小节点应该让 pre 的右孩子等于右子树最小节点的右孩子,即:pre.right = rightTreeMin.right ;如图右,当右子树最小节点不是 cur 的右孩子时,如删除节点15时,删除右子树最小节点应该让 pre 的左孩子等于右子树最小节点的右孩子,即:pre.left = rightTreeMin.right

在这里插入图片描述

同时,非递归方法还要对删除节点是根节点进行特殊判断,否则 pre 会出现空指针异常。对根节点进行判断时,不用考虑左右子树都不为空的情况,因为这种情况会对 pre 重新赋值,不会出现空指针异常。

最后的代码如下。

public TreeNode deleteNode(TreeNode root, int key) {
    
    
    if (root == null)
        return null;

    if (root.val == key) {
    
    
        if (root.left == null && root.right == null) {
    
    
            return null;
        } else if (root.left == null) {
    
    
            return root.right;
        } else if (root.right == null) {
    
    
            return root.left;
        }
    }

    TreeNode cur = root;
    TreeNode pre = null;
    while (cur != null) {
    
    
        if (key == cur.val) {
    
    
            // leaf
            if (cur.left == null && cur.right == null) {
    
    
                if (pre.left == cur)
                    pre.left = null;
                if (pre.right == cur)
                    pre.right = null;
            } else if (cur.left == null) {
    
    
                if (pre.left == cur)
                    pre.left = cur.right;
                if (pre.right == cur)
                    pre.right = cur.right;
            } else if (cur.right == null) {
    
    
                if (pre.left == cur)
                    pre.left = cur.left;
                if (pre.right == cur)
                    pre.right = cur.left;
            } else {
    
    
                TreeNode rightTreeMin = cur.right;
                pre = cur;
                while (rightTreeMin.left != null) {
    
    
                    pre = rightTreeMin;
                    rightTreeMin = rightTreeMin.left;
                }
                cur.val = rightTreeMin.val;
                // delete rightTreeMin
                if (pre == cur) {
    
    
                    pre.right = rightTreeMin.right;
                } else {
    
    
                    pre.left = rightTreeMin.right;
                }
            }
            break;
        } else if (key > cur.val) {
    
    
            pre = cur;
            cur = cur.right;
        } else {
    
    
            pre = cur;
            cur = cur.left;
        }
    }
    return root;
}

猜你喜欢

转载自blog.csdn.net/qq_41512783/article/details/110769270