二叉查找树的删除结点操作

二叉查找树:

二叉查找树(Binary Search Tree),(又二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

例子:


结点的删除操作:

分三种情况讨论:

结点为叶子结点时,直接删除,把父节点指向子节点的引用设为null

结点的度为1,分两种情况,判断是父节点的左子结点还是右子节点,把父节点的引用指向结点的子节点(子节点也要分左右子节点情况,相当于一共四种情况)

结点的度为2,由于二叉搜索树的特性,保证了某个结点的左子树的值都小于该节点,右子树的值都大于该节点,只需找到左子树中的最大值或者右子树中的最小值来替换该结点,即可保证节点删除后任为二叉搜索树。(下面代码中采用左子树的最大值代替结点)

代码实现:

  /*
    删除
    先找到元素,再删除
    分三种情况,删除的节点为叶子节点,此时直接删除,修改父节点的引用
    度为1的节点,删除后修改父节点的引用,指向子节点
    度为2的节点,删除后把左边最大的节点或者右边最小的节点替换到该节点
     */

    public static boolean delete(int x, TreeNodeInt T) {
        TreeNodeInt current = T;//需要删除的节点
        TreeNodeInt parent = null;//需要删除的节点的父节点
        boolean isLeftChild = true;//需要删除的节点是否为父节点的左子节点

        //通过该循环来找到要删除节点的位置和他的父节点
        while (true) {
            if (x == current.value) {
                break;
            } else if (x < current.value) {
                //删除的值小于当前节点
                //查看左子树
                isLeftChild = true;
                parent = current;
                current = current.lchild;

            } else {
                //删除的值大于当前节点
                //查看右子树
                isLeftChild = false;
                parent = current;
                current = current.rchild;
            }

            //找不到要删除的节点,直接返回null
            if (current == null) {
                return false;
            }
        }

        //分情况考虑
        //1.需要删除的节点为叶子节点
        if (current.lchild == null && current.rchild == null) {
            //如果该节点为根节点,把根节点设置为null
            if (current == T) {
                T = null;
            } else {
                //如果该叶节点时父节点的左子节点,将父节点的左子节点设置为null
                if (isLeftChild) {
                    parent.lchild = null;
                } else {
                    //如果该叶节点时父节点的右子节点,将父节点的右子节点设置为null
                    parent.rchild = null;
                }
            }

        }

        //2.需要删除的节点为度为1的节点,且该子节点为左子节点
        else if (current.rchild == null) {
            //如果该节点为根节点,将根节点的左子节点变为根节点
            if (current == T) {
                T = current.lchild;
            } else {
                //如果该节点是父节点的左子节点,则将该节点的左子节点变为父节点的左子节点
                if (isLeftChild) {
                    parent.lchild = current.lchild;
                }
                //如果该节点是父节点的右子节点,则将该节点的左子节点变为父节点的右子节点
                else {
                    parent.rchild = current.lchild;
                }
            }
        }

        //2.需要删除的节点为度为1的节点,且该子节点为右子节点
        else if (current.lchild == null) {
            //如果该节点为根节点,将根节点的右子节点变为根节点
            if (current == T) {
                T = current.rchild;
            } else {
                //如果该节点是父节点的左子节点,则将该节点的右子节点变为父节点的左子节点
                if (isLeftChild) {
                    parent.lchild = current.rchild;
                }
                //如果该节点是父节点的右子节点,则将该节点的右子节点变为父节点的右子节点
                else {
                    parent.rchild = current.rchild;
                }
            }
        }

        //3.需要删除的节点有两个子节点,需要寻找该节点的后续节点代替删除节点
        //即用左子树的最大值或者右子树的最小值代替该节点,通知删除左子树的最大值或者右子树的最小值
        else {
            //得到当前位置左边最小值代替他并删除左边最小值结点
            //由于此处的current为定位到要删除的位置,所以又写了一个函数来找到当前位置的继承人
            getSuccessor(current);

        }

        return true;
    }
 /*
    找到一个节点的继承人,即左边最大或右边最小,并删除继承人原来的位置

     */
    public static void getSuccessor(TreeNodeInt T){
        TreeNodeInt targetParent=T;
        TreeNodeInt targetNode=T.lchild;
        while (targetNode.rchild!=null){
            targetParent=targetNode;
            targetNode=targetNode.rchild;
            isLeft=false;
        }
        if (isLeft){
            targetParent.lchild=targetNode.lchild;
            T.value=targetNode.value;
            targetNode=null;
        }else {
            //当左边最大值有左结点时
            if (targetNode.lchild!=null){
                targetParent.rchild=targetNode.lchild;
                T.value=targetNode.value;
                targetNode=null;
            }else {
                //左边最大值为没有左结点时
                targetParent.rchild=null;
                T.value=targetNode.value;
                targetNode=null;
            }
        }
    }

 

总结:

对于二叉树,当操作涉及到左右子树时,很多情况需要判断是左子树还是右子树,需要进行分类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值