删除二叉树节点

本文详细解析了二叉树中删除节点的复杂过程,包括定位目标节点、判断节点类型及进行相应操作。针对不同类型的节点(叶子节点、单子节点、双子节点),提供了具体的删除策略,并附带代码实现,最后通过测试案例验证了删除功能的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:删除节点

删除节点比较复杂

步骤:

1.找到需要被删除的节点
2.判断该节点的类型
2.1该节点是叶子节点,直接修改父节点的引用值为null即可
2.2该节点有一个子节点,修改父节点得引用,将该节点的父节点的应用指向该节点的子节点(相当于隔开该节点)
2.3该节点有两个子节点,需要是由该节点的中序后继来替代该节点

节点的中序后继:

指的是比该节点大的且是最接近该节点的节点
图1

二:代码实现

1.创建节点Node
public class Node {

    //数据项
    long data;
    //左子节点
    Node leftChild;
    //右子节点
    Node rightChild;

    //构造
    public Node(long value){
        this.data = value;
    }
}

2.删除节点
//删除二叉树节点
public class Tree {
    //根节点
    public Node root;

    //插入节点
    public void insert(long value){
        //1.新建准备插入的节点
        Node newNode = new Node(value);
        //2.当前节点
        Node current = root;
        //3.父节点
        Node parent;

        //首次插入,根节点 = null
        if (root == null){
            root = newNode;
            return;
        }else{
            while (true){
                //非首次插入
                //父节点指向当前节点
                parent = current;
                //比较根节点和value的值大小
                if (current.data > value){
                    //根节点 > value , 向左走
                    current = current.leftChild;
                    //当走到叶子节点的时候
                    if (current == null){
                        //新节点插入 父节点的左子节点
                        parent.leftChild = newNode;
                        return;
                    }
                }else{
                    //向右走
                    current = current.rightChild;
                    //走到叶子节点
                    if (current == null){
                        //新节点插入 父节点的右子节点
                        parent.rightChild = newNode;
                        return;
                    }
                }
            }
        }
    }

    //删除节点
    public boolean deleteNode(long value){
        //引用当前节点
        Node current = root;
        //引用父节点
        Node parent = root;
        //判断是否为左子节点,默认true
        boolean isLeftChild = true;

        //1.查找节点
        while (current.data != value){
            parent = current;
            if (current.data > value){
                current = current.leftChild;
                isLeftChild = true;
            }else{
                current = current.rightChild;
                isLeftChild = false;
            }
            //如果找不到
            if (current == null){
                return false;
            }
        }

        //2.删除节点
        //2.1如果被删除的节点是叶子节点的情况
        if (current.leftChild == null && current.rightChild == null){
            //如果只有一个根节点,且刚好找到
            if (current == root){
                root = null;
            }
            if (isLeftChild){
                //如果是左子节点
                parent.leftChild = null;
            }else{
                //如果是右子节点
                parent.rightChild = null;
            }
        }
        //2.2如果被删除的节点有一个子节点的情况
        else if (current.leftChild != null && current.rightChild == null){
            //只有左子节点
            //如果找到的节点是根节点
            if (current == root){
                root = current.leftChild;
            }
            //还要判断是在根节点的左边还是右边
            else if (current.data < root.data){
                //被删除的节点在根节点的左边
                parent.leftChild = current.leftChild;
            }else{
                //被删除的节点在根节点的右边
                parent.rightChild = current.leftChild;
            }
        }else if (current.leftChild == null && current.rightChild != null){
            //只有右子节点
            //如果找到的节点是根节点
            if (current == root){
                root = current.rightChild;
            }
            //还要判断是在根节点的左边还是右边
            else if (current.data < root.data){
                //被删除的节点在根节点的左边
                parent.leftChild = current.rightChild;
            }else{
                //被删除的节点在根节点的右边
                parent.rightChild = current.rightChild;
            }
        }
        //2.3如果被删除的节点有两个子节点的情况
        else {
            //先找到该节点的中序后继节点:
            Node tmp = getReplaceNode(current);
            //现在tmp 就是中序后继节点
            //如果删除的是root节点
            if (current == root){
                root = tmp;
            }
            //不是根节点 , 那就判断该节点是在其父节点的左子节点还是在其父节点的右子节点
            else if (isLeftChild){
                //是左子节点
                parent.leftChild = tmp;
            }else{
                //是右子节点
                parent.rightChild = tmp;
            }
            //注意: 替换完成后,还需要引用回旧节点的左节点数据
            //其右节点数据已经在中序后继方法中引用回来了,这里无需再写
            tmp.leftChild = current.leftChild;
        }
        return true;
    }

    //查找中序后继方法
    public static Node getReplaceNode(Node deleteNode){
        Node replaceNode = deleteNode;
        Node replaceParentNode = deleteNode;
        Node current = deleteNode.rightChild;

        while (current != null){
            replaceParentNode = replaceNode;
            replaceNode = current;
            current = current.leftChild;
        }
        //判断中序后继节点是否是deleteNode的右子节点(这种情况是因为删除节点的右子节点没有左子节点)
        if (replaceNode != deleteNode.rightChild){
            //中序后继节点的右子节点成了中序后继节点的父节点的左子节点
            replaceParentNode.leftChild = replaceNode.rightChild;
            //同时被删除节点的右子节点成了中序后继节点的右节点
            replaceNode.rightChild = deleteNode.rightChild;
        }
        return replaceNode;
    }

    //中序遍历
    //参数localNode 代表根节点
    public void inOrder(Node localNode){
        if (localNode != null){
            //1.中序遍历左子树
            inOrder(localNode.leftChild);
            //2.访问根节点
            System.out.println(localNode.data);
            //3.中序遍历右子树
            inOrder(localNode.rightChild);

        }
    }

}

3.测试
public class Test {
    public static void main(String[] args) {

        Tree tree = new Tree();

        //插入数据
        tree.insert(8);
        tree.insert(3);
        tree.insert(6);
        tree.insert(10);
        tree.insert(1);
        tree.insert(9);
        tree.insert(100);

        //中序遍历
        tree.inOrder(tree.root); // 1 3 6 8 9 10 100

        //1.第一种情况:被删除的节点是叶子节点
        boolean b = tree.deleteNode(1);
        if (b){
            System.out.println("删除成功");
        }else{
            System.out.println("找不到节点");
        }
        //中序遍历
        tree.inOrder(tree.root); // 3 6 8 9 10 100

        //2.第二种情况:被删除的节点有一个子节点
        boolean b1 = tree.deleteNode(3);
        if (b1){
            System.out.println("删除成功");
        }else{
            System.out.println("找不到节点");
        }
        //中序遍历
        tree.inOrder(tree.root); // 6 8 9 10 100

        //3.第三种情况:被删除的节点有两个子节点
        boolean b2 = tree.deleteNode(10);
        if (b2){
            System.out.println("删除成功");
        }else{
            System.out.println("找不到节点");
        }
        //中序遍历
        tree.inOrder(tree.root); //

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值