二叉排序树代码实现(java版)(下)

简介: 二叉排序树代码实现(java版)

五、查找节点

1、查找某个节点

(1)在树类中添加查找方法,跟上面的写法一样,根节点不存在返回空,存在调用节点的查找方法。

    public Node search(int value) {
        if (root == null) {
            return null;
        }
        return root.search(value);
    }

(2)在节点类中添加查找方法。我们先判断当前节点的值是否与要查的值相等,相等的话直接返回当前节点就结束了,本来不想等的话,我们应该同时判断左节点、右节点的值是否符合,但这是二叉排序数,左子树的值肯定小于右子树的值,我们只需要将父节点的值与所传值进行比较,所传值大,我们去右边找,反之亦然,这样的效率就相当于我们写的二分查找,节约了一半的时间(只有平衡二叉树才能真正达到)

    public Node search(int value) {
        if (this.value == value) {
            return this;
        } else if (this.value > value) {
            if (this.leftNode != null) {
                return leftNode.search(value);
            }
        } else if (this.value < value) {
            if (this.rightNode != null) {
                return this.rightNode.search(value);
            }
        }
        return null;
    }

2、查找某个节点的父节点

(1)在树类中添加查找父节点方法,跟上面的写法一样,根节点不存在返回空,存在调用节点的父节点查找方法。

    public Node searchParent(int value) {
        if (root == null) {
            return null;
        }
        return root.searchParent(value);
    }

(2)在节点类中添加查找父节点方法,与查找某个节点的方法区别是,对于查找父节点,我们拿到当前节点后,比较的是当前节点的子节点值是否与所传参数值相等,相等返回当前节点。因为子节点与所传值相等了,当前这个节点就是父节点了。

   //查找该节点的父节点,如果是根节点以及不存在值将会返回null
    public Node searchParent(int value) {
        //如果该Node左节点或者右节点匹配参数值,返回当前节点
        if ((this.leftNode != null && this.leftNode.value == value) || (this.rightNode != null && this.rightNode.value == value)) {
            return this;
        } else {
            //该节点的值大于参数值,去左边找
            if (this.value > value && this.leftNode != null) {
                return leftNode.searchParent(value);
            } else if (this.value < value && this.rightNode != null) {
                return rightNode.searchParent(value);
            }
        }
        return null;
    }

六、删除节点

1、其删除一个节点需要考虑对应节点的状态,具体的说就是,是否存在左右节点,等等。需要按照以下情况讨论。

(1).查找待删除节点,在查找的同时需要记录一下待删除节点的父亲。

(2).如果待删除节点的左右节点都不存在,那么直接删除。

(3).如果待删除节点左子树存在右子树不存在,或者左子树不存在右子树存在。直接将其子树中存在的一边候补上来即可。


(4).如果待删除节点左右子树都在,这个情况是最复杂的。需要按照二叉排序树的性质从其左子树或者有子树中选择节点补到待删除节点的位置。 如果从左子树中选,就应该选择左子树中最右边的那个叶子节点(即中序排序中待删除节点的前驱节点) 如果从右子树中选,就应该选择有子树中最左边的那个叶子节点(即中序排序中待删除节点的后继节点)。


2、代码如下

(1)查找当前节点和查找父节点的方法在上面有提到。


(2)当待删除节点同时左右子树都存在时,我们要是选择左子树上的节点补上去,根据定义,为了保证删除后还是一个二叉排序数,肯定选择中序排序时,该删除节点的前一个,由定义可知,前一个肯定是左子树最右边的叶子节点(前躯),可自行实现,此处实现为查找出待删除节点右子树中找中序排序的后继节点。代码见下一步。

    public void delete(int value) {
        //查找待删除节点
        Node target = search(value);
        if (target != null) {
            //在查找的同时需要记录一下待删除节点的父亲
            Node parent = searchParent(value);
            //2.如果待删除节点的左右节点都不存在,那么直接删除。
            if (target.leftNode == null && target.rightNode == null) {
                if (parent.leftNode != null && parent.leftNode.value == value) {
                    parent.leftNode = null;
                } else {
                    parent.rightNode = null;
                }
            //3、待删除的左右节点都存在情况
            } else if (target.rightNode != null && target.leftNode != null) {
                //此处删除后继节点,注意前驱和后继节点是中序排列后的该删除节点的前一个或者后一个节点。
                int min = deleteMinNode(target.rightNode);
                target.value = min;
                //待删除节点左子树存在右子树不存在,直接将其子树中存在的一边候补上来即可
            } else {
                if (target.rightNode != null) {
                    if (parent.leftNode != null && parent.leftNode.value == value) {
                        parent.leftNode = target.rightNode;
                    } else {
                        parent.rightNode = target.rightNode;
                    }
                } else {
                    if (parent.leftNode != null && parent.leftNode.value == value) {
                        parent.leftNode = target.leftNode;
                    } else {
                        parent.rightNode = target.leftNode;
                    }
                }
            }
        }
    }

(3)待删除节点右子树中找中序排序的后继节点方法,找到后删除并返回节点值即可,但是要考虑两种情况,一是该后继节点右子树可能存在,要是存在我们需要返回后继节点值后,把后继节点右子树节点补到后继节点上,我们直接再次调用删除节点方法,把后继节点传进去,即可考虑到这种情况,代码如下:

    private int deleteMinNode(Node node) {
        Node target = node;
        while (target.leftNode != null) {
            target = target.leftNode;
        }
        //删除该节点
        delete(target.value);
        return target.value;
    }

七、测试

1、调用以上方法进行灵活测试即可,示例如下,其余自行实现即可。

    public static void main(String[] args) {
        int[] arr = new int[]{7, 3, 10, 12, 5, 1, 9};
        BinarySortTree tree = new BinarySortTree();
        for (int i : arr) {
            //添加节点
            tree.addNode(new Node(i));
        }
        //遍历
        tree.middleSort();
        //查找某个节点
        Node search = tree.search(9);
        //删除某个节点
        tree.delete(3);
    }

八、总结

     以上就是对于二叉排序树java版实现的总结,

目录
相关文章
|
5月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
453 6
|
6月前
|
IDE Java 关系型数据库
Java 初学者学习路线(含代码示例)
本教程为Java初学者设计,涵盖基础语法、面向对象、集合、异常处理、文件操作、多线程、JDBC、Servlet及MyBatis等内容,每阶段配核心代码示例,强调动手实践,助你循序渐进掌握Java编程。
793 3
|
6月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
734 3
|
6月前
|
Java API 开发工具
【Azure Developer】Java代码实现获取Azure 资源的指标数据却报错 "invalid time interval input"
在使用 Java 调用虚拟机 API 获取指标数据时,因本地时区设置非 UTC,导致时间格式解析错误。解决方法是在代码中手动指定时区为 UTC,使用 `ZoneOffset.ofHours(0)` 并结合 `withOffsetSameInstant` 方法进行时区转换,从而避免因时区差异引发的时间格式问题。
320 4
|
7月前
|
人工智能 监控 安全
智慧工地解决方案,java智慧工地程序代码
智慧工地系统融合物联网、AI、大数据等技术,实现对施工现场“人、机、料、法、环”的全面智能监控与管理,提升安全、效率与决策水平。
215 2
|
5月前
|
Java 数据处理 API
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
316 115
|
5月前
|
安全 Java 编译器
为什么你的Java代码需要泛型?类型安全的艺术
为什么你的Java代码需要泛型?类型安全的艺术
231 98
|
6月前
|
Java
java入门代码示例
本文介绍Java入门基础,包含Hello World、变量类型、条件判断、循环及方法定义等核心语法示例,帮助初学者快速掌握Java编程基本结构与逻辑。
518 0
|
8月前
|
Java 数据安全/隐私保护
快手小红书抖音留痕工具,自动留痕插件工具,java代码开源
这个框架包含三个核心模块:主操作类处理点赞评论、配置管理类和代理管理类。使用时需要配合