数据结构,二叉搜索树(三)

简介: 本文讲解:二叉搜索树的删除节点。

 2. 删除结点

删除二叉搜索树的结点,我们必需在删除该结点后保证这个二叉树还是为二叉搜索树,因此这样的操作是比较难的。

二叉搜索树的难点(重点)就在于删除节点,我们可以设根节点为 root 待删除的节点为 cur,待删除的节点的双亲结点为 parent。因此会出以下情况:

    1. cur.left为null时
    2. cur.right为null时
    3. cur.left不为空并且cur.right不为空时:

    (1).cur.left为null

    当cur.left为null时分为3种情况:

    情况1cur 是 root 时,需要将root=cur.right。

    image.gif编辑

    if (cur.left == null) {
            if (cur == root) {
                root = cur.right;
            }
        }

    image.gif


    情况2cur不是root,cur是parent.left时,我们需要将parent.left = cur.right。

    image.gif编辑

    if (cur.left == null) {
            if (cur == parent.left) {
                parent.left = cur.right;
            }
        }

    image.gif


    情况3cur不是root,cur是parent.right,我们需要将parent.right = cur.right。

    image.gif编辑

    if (cur.left == null) {
            if (cur == parent.right) {
                parent.right = cur.right;
            }
        }

    image.gif

    因此把cur.left为null的三种情况综合起来:

    if (cur.left == null) {
                    if (cur == root) {
                        root = cur.right;
                    }else if(cur == parent.left) {
                        parent.left = cur.right;
                    }else {
                        parent.right = cur.right;
                    }
                 }

    image.gif


    (2).cur.right为null

    cur.right为null,也分为3种情况:

    情况1cur是root,root=cur.left

    image.gif编辑

    if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            }
        }

    image.gif


    情况2cur不是root,cur是parent.left,parent.left = cur.left

    image.gif编辑

    if(cur.right == null) {
            if(cur == parent.left) {
                parent.left = cur.left;
            }
        }

    image.gif


    情况3cur不是root,cur是parent.right,parent.right = cur.left

    image.gif编辑

    if(cur.right == null) {
            if(cur == parent.right) {
                parent.right = cur.left;
            }
        }

    image.gif

    cur.right = null的三种情况综合起来,就能写出以下代码:

    if(cur.right == null) {
                    if (cur == root) {
                        root = cur.left;
                    }else if(cur == parent.left) {
                        parent.left = cur.left;
                    }else {
                        parent.right = cur.left;
                    }
                 }

    image.gif


    (3).cur.left不为空且cur.right不为空

    当删除的结点左右子树都不为空的情况下,我们就得使用“替换法”来替换被删节点,被替换的节点为被删除节点的右子树的左侧子树的最后一个左子树是最适合用来替换被删节点的,无论哪种情况都是这样,大家可以自行画图测试一番。

    目前我们知道了 cur 为要删除的结点,因此替换的结点我们设为 target ,替换节点的双亲结点为 targetParent ,设置替换节点双亲结点是为了当替换节点为空时,我们能找到替换节点!


    当 cur.right 的最左子树为 target 时

    程序的结束条件为:target.left != null ,直接将该树的值赋值给cur的值即 cur.val = target.val。替换节点删除操作为:targetParent.left = target.right

    image.gif编辑


    cur.right 的最左侧不为 target 时

    程序的结束条件为:target.left != null ,直接将该树的值赋值给cur的值即 cur.val = target.val。替换节点删除操作为:targetParent.right = target.right

    image.gif编辑

    因此,综合上方把cur.left不为空且cur.right不为空可以写成以下代码:

    TreeNode target = cur.right;
    TreeNode targetParent = cur;
        while (target.left != null) {//终止条件为最左侧为空
            targetParent = target;
            target = target.left;
        }
            cur.val = target.val;//把cur的值替换为target的值
            if (target == targetParent.left) {
                    targetParent.left = target.right;//最左侧值等于target
            }else {
                    targetParent.right = target.right;//最左侧值不等于target
            }

    image.gif


    把删除节点中所有代码综合起来,我们就能写出完整的删除操作。当然,我们得先找到删除的节点又使用到了 findNode 的操作,我把删除节点的操作封装到一个名为 removeNode 的方法里面,以下为完整代码:

    //查找节点
        public void delNode(int key) {
            TreeNode cur = root;
            TreeNode parent = null;
            while(cur != null) {
                if (cur.val == key) {
                    removeNode(cur,parent);//调用删除节点方法
                }else if(cur.val > key) {
                    parent = cur;
                    cur = cur.left;
                    removeNode(cur,parent);//调用删除节点方法
                }else {
                    parent = cur;
                    cur = cur.right;
                    removeNode(cur,parent);//调用删除节点方法
                }
            }
        }
        //删除节点
        public void removeNode(TreeNode parent,TreeNode cur) {
            while (cur != null) {
                if (cur.left == null) {
                    if (cur == root) {
                        root = cur.right;
                    }else if(cur == parent.left) {
                        parent.left = cur.right;
                    }else {
                        parent.right = cur.right;
                    }
                }else if(cur.right == null) {
                    if (cur == root) {
                        root = cur.left;
                    }else if(cur == parent.left) {
                        parent.left = cur.left;
                    }else {
                        parent.right = cur.left;
                    }
                }else{
                    TreeNode target = cur.right;
                    TreeNode targetParent = cur;
                    while (target.left != null) {
                        targetParent = target;
                        target = target.left;
                    }
                    cur.val = target.val;
                    if (target == targetParent.left) {
                        targetParent.left = target.right;
                    }else {
                        targetParent.right = target.right;
                    }
                }
            }
        }

    image.gif

    相关文章
    |
    6月前
    |
    算法
    【数据结构】二叉搜索树
    【数据结构】二叉搜索树
    42 2
    |
    2月前
    |
    存储 Java Serverless
    【数据结构】哈希表&二叉搜索树详解
    本文详细介绍了二叉搜索树和哈希表这两种数据结构。二叉搜索树是一种特殊二叉树,具有左子树节点值小于根节点、右子树节点值大于根节点的特点,并且不允许键值重复。文章给出了插入、删除和搜索等方法的具体实现。哈希表则通过哈希函数将键名映射为数组下标,实现快速查找,其插入、删除和查找操作时间复杂度理想情况下为O(1)。文中还讨论了哈希函数的设计原则、哈希冲突的解决方法及哈希表的实现细节。
    56 8
    【数据结构】哈希表&二叉搜索树详解
    |
    1月前
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(三)
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现
    |
    1月前
    |
    存储
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(二)
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现
    |
    1月前
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(一)
    【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现
    |
    1月前
    【数据结构】二叉搜索树的功能实现详解
    【数据结构】二叉搜索树的功能实现详解
    28 0
    |
    5月前
    数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)
    数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)
    52 2
    |
    5月前
    |
    机器学习/深度学习
    数据结构学习记录——堆的小习题(对由同样的n个整数构成的二叉搜索树(查找树)和最小堆,下面哪个说法是不正确的)
    数据结构学习记录——堆的小习题(对由同样的n个整数构成的二叉搜索树(查找树)和最小堆,下面哪个说法是不正确的)
    38 1
    |
    4月前
    |
    存储
    【数据结构】AVL树——平衡二叉搜索树
    【数据结构】AVL树——平衡二叉搜索树
    |
    4月前
    |
    存储 Linux 数据库
    【数据结构】二叉搜索树——高阶数据结构的敲门砖
    【数据结构】二叉搜索树——高阶数据结构的敲门砖