二叉树知识之3节点的删除

简单二叉树删除的思路

简单删除的规定

  1. 如果删除的是叶子节点,则删除该节点
  2. 如果删除的节点是非叶子节点,则将该节点的子树一起删除

简单删除的思路

  1. 先判断是是不是空树,是空树则直接返回,
  2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
  3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
  4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
  5. 如果第3,4步没有删除节点,则将左子树进行递归删除
  6. 如果第5步也没有删除节点,则应当向右子树进行递归删除

简单删除的代码实现(以删除4号节点为例)

找到4号节点并且删除4号节点时,在进行前序遍历时应该是1-2-3:下面进行仿真
删除4号节点为例

在节点中的简单删除

public void delete(int no){
        //* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
        if(this.left!=null&&this.left.no==no){
            this.left=null;
            return;
        }
        //4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
        if(this.right!=null&this.right.no==no){
            this.right=null;
            return;
        }
        //5如果第3,4步没有删除节点,则将左子树进行递归删除
        if(this.left!=null){
            this.left.delete(no);
        }
        //6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
        if(this.right!=null){
            this.right.delete(no);
        }
    }

在二叉树的结构中进行删除的步骤实现

public void delete(int no){
        //先判断该树的根节点是否为空
        if(root!=null){
            //判断该根节点是否和目标一致,如果一致则直接删除,置为空
            if(root.no==no){
                root=null;
                //如果当前根节点不是要删除的节点,则需要递归删除
            }else {
                root.delete(no);
            }
         //如果为空则直接返回啦!
        }else {
            System.out.println("该树为空不能删除!");
            return;
        }
    }

测试代码

package com.njupt.binaryTree;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/07/23/11:16
 * @Description:
 */
public class SimpleDelete {
    public static void main(String[] args) {

        BinaryTr binary = new BinaryTr();
        NodeND node1 = new NodeND(1, "吴吴");
        NodeND node2 = new NodeND(2, "亦亦");
        NodeND node3 = new NodeND(3, "凡凡");
        NodeND node4 = new NodeND(4, "签签");
        NodeND node5 = new NodeND(5, "word");
        NodeND node6 = new NodeND(6, "very big");
        node1.left = node2;
        node1.right = node4;
        node2.left = node3;
        node4.left = node5;
        node4.right = node6;
        //给根节点赋值
        binary.root = node1;
        System.out.println("没删除4号节点之前的前序遍历:");
        binary.preSearch();
        binary.delete(4);
        System.out.println("删除4号节点之后的前序遍历");
        binary.preSearch();

    }
}

class BinaryTr {
    public NodeND root;

    //前序遍历的方法
    public void preSearch() {
        if (root == null) {
            System.out.println("当前树为空");
            return;
        } else {
            this.root.pre();
        }
    }

    //删除节点的方法
    public void delete(int no) {
        //先判断该树的根节点是否为空
        if (root != null) {
            //判断该根节点是否和目标一致,如果一致则直接删除,置为空
            if (root.no == no) {
                root = null;
                //如果当前根节点不是要删除的节点,则需要递归删除
            } else {
                root.delete(no);
            }
            //如果为空则直接返回啦!
        } else {
            System.out.println("该树为空不能删除!");
            return;
        }
    }
}

class NodeND {
    public int no;
    public String name;
    public NodeND left;
    public NodeND right;

    public NodeND(int no, String name) {
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Node1{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

    /**
     * 1. 先判断是是不是空树,是空树则直接返回,
     * 2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
     * 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
     * 4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
     * 5. 如果第3,4步没有删除节点,则将左子树进行递归删除
     * 6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
     */
    public void delete(int no) {
        //* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        //4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
        if (this.right != null & this.right.no == no) {
            this.right = null;
            return;
        }
        if (this.left != null) {
            this.left.delete(no);
        }
        if (this.right != null) {
            this.right.delete(no);
        }
    }

    //前序遍历
    public void pre() {
        //跟
        System.out.println(this);
        //左
        if (this.left != null) {
            this.left.pre();
        }
        //右
        if (this.right != null) {
            this.right.pre();
        }
    }

}

测试结果:

没删除4号节点之前的前序遍历:
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=5, name='word'}
Node1{no=6, name='very big'}
删除4号节点之后的前序遍历
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}

Process finished with exit code 0

复杂二叉树的删除

复杂二叉树的删除规定

规定:
如果删除的是叶子节点,则直接删除。
如果删除的是非叶子节点,则:

  1. 若非叶子节点的子节点只有一个,则将该子节点直接代替删除的节点
  2. 若非叶子结点的子节点有两个,则让左子节点代替原来删除的节点

复杂二叉树的删除思路

  1. 先判断是是不是空树,是空树则直接返回,
  2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
  3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则
    1. 先判断是否为叶子节点,如果是叶子节点,则将this.left=null并且返回(结束递归删除)
    2. 如果不是叶子节点,则有三种情况:
    a. 有右子节点没有左子节点:将删除的节点置为该节点的右子节点:结束递归
    b.有左子节点没有右子节点:将删除的节点置为该节点的左子节点:结束递归
    c.左右子节点都有 :将删除的节点置为该节点的左子节节点:结束递归
  4. 如果当前节点的右子节点不为空,且就是要删除的节点则
    1. 先判断是否为叶子节点,如果是叶子节点,则将this.right=null并且返回(结束递归删除)
    2. 如果不是叶子节点,则有三种情况:
    a. 有右子节点没有左子节点:将删除的节点置为该节点的右子节点
    b.有左子节点没有右子节点:将删除的节点置为该节点的左子节点
    c.左右子节点都有 :将删除的节点置为该节点的左子节节
  5. 如果第3,4步没有删除节点,则将左子树进行递归删除
  6. 如果第5步也没有删除节点,则应当向右子树进行递归删除

复杂删除的代码实现(以删除5号节点为例)

删除5号节点
主要的核心代码实现:

public void betterDelete(int no) {
        //1假设在左边找到了,先遍历左子节点,如果左边不为空,并且左边就是要删除的节点,则需要判断删除节点的左边是否为空
        if (this.left != null && this.left.no == no) {
            //1如果删除的就是叶子节点,即删除节点的左右都为空,则直接置空即可
            if (this.left.left == null && this.left.right == null) {
                this.left = null;
                return;
                //2如果删除的节点是非叶子节点,只有一个的情况,即左子节点为空,右子节点不为空
            } else if (this.left.left == null && this.left.right != null) {
                this.left = this.left.right;
                return;
                //剩下的情况是左子节点不为空右子节点为空和左右子节点都不为空,此时这两种情况都是将此删除节点的左子节点代替原来删除的节点
            } else {
                this.left = this.left.left;
                return;
            }
        }
        //如果左子树没有找到,假设找右子树找到了
        if (this.right != null && this.right.no == no) {
            //如果要删除的就是叶子节点,则将删除的节点直接置空
            if (this.right.left == null && this.right.right == null) {
                this.right = null;
                return;
                //如果删除的不是叶子节点,则有三种情况,第一种是左子节点没有,右子节点有
            } else if (this.right.left == null && this.right.right != null) {
                //将右子节点直接放到删除的位置
                this.right = this.right.right;
                return;
                //按照规则,剩下的都是把左子节点的值放到要删除的节点
            } else {
                this.right = this.right.left;
                return;
            }
        }
        //如果左节点和右节点都不是,则递归查找目标节点
        if (this.left != null) {
            this.left.betterDelete(no);
        }
        if (this.right != null) {
            this.right.betterDelete(no);
        }

    }

测试代码

package com.njupt.binaryTree;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/07/23/11:16
 * @Description:
 */
public class SimpleDelete {
    public static void main(String[] args) {

        BinaryTr binary = new BinaryTr();
        NodeND node1 = new NodeND(1, "吴吴");
        NodeND node2 = new NodeND(2, "亦亦");
        NodeND node3 = new NodeND(3, "凡凡");
        NodeND node4 = new NodeND(4, "签签");
        NodeND node5 = new NodeND(5, "word");
        NodeND node6 = new NodeND(6, "very big");
        NodeND node7 = new NodeND(7, "55");
        NodeND node8 = new NodeND(8, "11");
        NodeND node9 = new NodeND(9, "烦烦");
        NodeND node10 = new NodeND(10, "签签");

        node1.left = node2;
        node1.right = node4;
        node2.left = node3;
        node4.left = node5;
        node4.right = node6;
        node5.left=node7;
        node5.right=node10;
        node7.left=node8;
        node7.right=node9;
        //给根节点赋值
        binary.root = node1;
        /*
        System.out.println("没删除4号节点之前的前序遍历:");
        binary.preSearch();
        binary.delete(4);
        System.out.println("利用简单删除4号节点之后的前序遍历");
        binary.preSearch();*/

        System.out.println("没删除5号节点之前的前序遍历:");
        binary.preSearch();
        binary.betterDelete(5);
        System.out.println("利用复杂规则删除5号节点之后的前序遍历");
        binary.preSearch();



    }
}

class BinaryTr {
    public NodeND root;

    //前序遍历的方法
    public void preSearch() {
        if (root == null) {
            System.out.println("当前树为空");
            return;
        } else {
            this.root.pre();
        }
    }

    //删除节点的方法
    public void delete(int no) {
        //先判断该树的根节点是否为空
        if (root != null) {
            //判断该根节点是否和目标一致,如果一致则直接删除,置为空
            if (root.no == no) {
                root = null;
                //如果当前根节点不是要删除的节点,则需要递归删除
            } else {
                root.delete(no);
            }
            //如果为空则直接返回啦!
        } else {
            System.out.println("该树为空不能删除!");
            return;
        }
    }
    //按照第二个规则删除的方法
    public void betterDelete(int no){
        //先判断该树的根节点是否为空
        if (root != null) {
            //判断该根节点是否和目标一致,如果一致则直接删除,置为空
            if (root.no == no) {
                root = null;
                //如果当前根节点不是要删除的节点,则需要递归删除
            } else {
                root.betterDelete(no);
            }
            //如果为空则直接返回啦!
        } else {
            System.out.println("该树为空不能删除!");
            return;
        }
    }
}

class NodeND {
    public int no;
    public String name;
    public NodeND left;
    public NodeND right;

    public NodeND(int no, String name) {
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Node1{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

    /**
     * 1. 先判断是是不是空树,是空树则直接返回,
     * 2. 该树的root节点是不是要删除的节点,如果是root节点,则直接将整个树置为null
     * 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
     * 4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
     * 5. 如果第3,4步没有删除节点,则将左子树进行递归删除
     * 6. 如果第5步也没有删除节点,则应当向右子树进行递归删除
     */
    public void delete(int no) {
        //* 3. 删除时先找到该要删除的节点的上一个节点,如果当前节点的左子节点是要删除的节点,则将this.left=null并且返回(结束递归删除)
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        //4. 如果当前节点的右子节点不为空,且就是要删除的节点则将this.right=null;并且返回(结束递归删除)
        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }
        if (this.left != null) {
            this.left.delete(no);
        }
        if (this.right != null) {
            this.right.delete(no);
        }
    }
    /**
     * 规定:
     * 如果删除的是叶子节点,则直接删除。
     * 如果删除的是非叶子节点,则:
     * 1. 若非叶子节点的子节点只有一个,则将该子节点直接代替删除的节点
     * 2. 若非叶子结点的子节点有两个,则让左子节点代替原来删除的节点
     *
     * */
    public void betterDelete(int no) {
        //1假设在左边找到了,先遍历左子节点,如果左边不为空,并且左边就是要删除的节点,则需要判断删除节点的左边是否为空
        if (this.left != null && this.left.no == no) {
            //1如果删除的就是叶子节点,即删除节点的左右都为空,则直接置空即可
            if (this.left.left == null && this.left.right == null) {
                this.left = null;
                return;
                //2如果删除的节点是非叶子节点,只有一个的情况,即左子节点为空,右子节点不为空
            } else if (this.left.left == null && this.left.right != null) {
                this.left = this.left.right;
                return;
                //剩下的情况是左子节点不为空右子节点为空和左右子节点都不为空,此时这两种情况都是将此删除节点的左子节点代替原来删除的节点
            } else {
                this.left = this.left.left;
                return;
            }
        }
        //如果左子树没有找到,假设找右子树找到了
        if (this.right != null && this.right.no == no) {
            //如果要删除的就是叶子节点,则将删除的节点直接置空
            if (this.right.left == null && this.right.right == null) {
                this.right = null;
                return;
                //如果删除的不是叶子节点,则有三种情况,第一种是左子节点没有,右子节点有
            } else if (this.right.left == null && this.right.right != null) {
                //将右子节点直接放到删除的位置
                this.right = this.right.right;
                return;
                //按照规则,剩下的都是把左子节点的值放到要删除的节点
            } else {
                this.right = this.right.left;
                return;
            }
        }
        //如果左节点和右节点都不是,则递归查找目标节点
        if (this.left != null) {
            this.left.betterDelete(no);
        }
        if (this.right != null) {
            this.right.betterDelete(no);
        }

    }

    //前序遍历
    public void pre() {
        //跟
        System.out.println(this);
        //左
        if (this.left != null) {
            this.left.pre();
        }
        //右
        if (this.right != null) {
            this.right.pre();
        }
    }

}

测试结果:
在这里插入图片描述
从图中可以看出,按照规则删除5号节点和后,左边子节点7就代替了5号节点的位置。

没删除5号节点之前的前序遍历:
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=5, name='word'}
Node1{no=7, name='55'}
Node1{no=8, name='11'}
Node1{no=9, name='烦烦'}
Node1{no=10, name='签签'}
Node1{no=6, name='very big'}
利用复杂规则删除5号节点之后的前序遍历
Node1{no=1, name='吴吴'}
Node1{no=2, name='亦亦'}
Node1{no=3, name='凡凡'}
Node1{no=4, name='签签'}
Node1{no=7, name='55'}
Node1{no=8, name='11'}
Node1{no=9, name='烦烦'}
Node1{no=6, name='very big'}

Process finished with exit code 0
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值