Serialization and Deserialization of a Binary Tree in Java2025 年 5 月 7 日 | 阅读 10 分钟 序列化是将数据结构(如二叉树)转换为可以存储或传输的格式,然后稍后重新构造的过程。反序列化是相反的过程,将序列化格式转换回原始数据结构。 对于二叉树来说,关键挑战在于如何编码树的结构(包括值和不存在节点的 null 值),以便能够准确地重新构造它。 序列化
反序列化
方法 1:使用“Null 标记”进行序列化和反序列化的前序遍历算法步骤 1. 序列化算法 输入:二叉树的根节点。 输出:表示树的序列化字符串。 步骤 1.1:初始化一个空的 StringBuilder 来存储序列化结果。 步骤 1.2:定义一个辅助函数 `serializeHelper(node, sb)`
步骤 2. 反序列化算法 输入:表示二叉树的序列化字符串。 输出:重构二叉树的根节点。 步骤 2.1:按逗号分隔符分割输入字符串,创建节点值列表。 步骤 2.2:定义一个辅助函数 `deserializeHelper(list)`
步骤 3. 可选的树打印算法 输入:二叉树的根节点。 输出:树的层序表示,用于调试或可视化。 步骤 3.1:初始化一个队列,并将根节点添加到其中。 步骤 3.2:当队列不为空时
步骤 3.3:处理完所有节点后停止。 步骤 3.4:清理和优化树的表示 完成层序遍历并打印节点值后,生成的输出可能包含不必要的占位符,例如遍历末尾的“null”值,这些值代表非存在的子节点。为了使树的表示更清晰、更简洁,可以移除这些多余的值。 识别不必要的 Null 值:检查打印的输出,找出末尾的“null”值。这些是树底层不存在的节点的占位符。 移除冗余 Null 值:从输出末尾开始,移除这些末尾的“null”条目,直到遇到最后一个有意义的节点(非 null 值)。这样可以确保表示反映树的实际结构。 组织和呈现输出:将清理后的值以易于阅读的格式组织起来。例如 为了简单起见,使用一个由逗号分隔的单行。 或者,按层级对值进行分组,以更清晰地显示树结构。 增强可视化:如果需要用于调试,可以添加每个层级的简短描述,或在对应于每个树层级的节点组之间提供视觉间隔。 文件名:BinaryTreeSerializer.java 输出 Serialized Tree: 1,2,null,null,3,4,null,null,5,null,null, Deserialized Tree (Level-order): 1 2 3 null null 4 5 null null null null 时间和空间复杂度分析时间复杂度 序列化
反序列化
空间复杂度 序列化
反序列化
方法 2:用于序列化和反序列化的层序遍历算法序列化算法步骤 1:初始化:检查 Null 树:在开始序列化过程之前,首先检查树是否为 null。如果树为空(即根节点为 null),则直接返回“null”作为序列化输出。 步骤 2:创建 StringBuilder:为了存储序列化数据,初始化一个 StringBuilder。这将使我们能够高效地将值附加到序列化字符串。 步骤 3:层序遍历:用于遍历的队列:为了按层序(广度优先)遍历树,我们使用队列。队列遵循先进先出(FIFO)原则,这对于层序遍历非常理想。 入队根节点:首先将根节点添加到队列。 遍历树:当队列不为空时,重复以下步骤 出队一个节点:从队列中移除队首节点。将处理此节点。 步骤 4:检查 Null 节点:如果当前节点为 null,则将“null,” 附加到 StringBuilder。这表示树中该位置缺少一个节点。 添加非 Null 节点的值:如果节点不为 null,则将节点的值后跟一个逗号,附加到 StringBuilder。 处理完节点后,将其左子节点和右子节点添加到队列(无论它们是 null 还是非 null)。这确保我们在序列化输出中正确地表示所有子节点。 步骤 4.1:修剪末尾的逗号:一旦所有节点(包括表示缺失节点的 null 节点)都已处理并添加到 StringBuilder 中,序列化字符串的末尾可能会有一个额外的末尾逗号。为了清理结果,移除末尾的逗号。这确保最终字符串格式正确,没有不必要的字符。 步骤 5:完成序列化:继续此层序遍历,直到处理完所有节点,包括表示缺失子节点的 null 节点。遍历完成后,将 StringBuilder 的内容转换为字符串并返回,作为树的序列化表示。 反序列化算法步骤 1:初始设置:检查 Null 输入:首先检查输入字符串是否为“null”。如果是,则返回 null,因为这表示一个空树。 步骤 1.1:分割输入字符串:按逗号分隔符分割输入字符串,以获取节点值列表。此列表将用于逐个节点地重构树。 步骤 2:重构树:创建根节点:使用列表中的第一个值来创建根节点。如果该值为“null”,则表示树为空,应返回 null。 步骤 3:用于树构造的队列:初始化一个队列并将根节点添加到其中。此队列将帮助逐层构建树,类似于序列化中使用的队列。 步骤 3.1:构建树:逐层节点构造:当队列中有节点时,重复以下步骤 出队一个节点:从队列中移除队首节点。分配左子节点:从列表中取下一个值并检查 如果该值为“null”,则当前节点的左子节点为 null。否则,用当前值创建一个新节点并将其添加到队列。 步骤 4:分配右子节点:同样,从列表中取下一个值并检查 如果该值为“null”,则当前节点的右子节点为 null。否则,用当前值创建一个新节点并将其添加到队列。 步骤 5:返回重构的树:一旦列表中的所有值都已处理完毕,并且整个树已重构,则返回根节点。该节点表示已完全重构的二叉树。 可选的树打印算法此步骤是可选的,但有助于调试或可视化树结构。 步骤 1:用于打印的层序遍历:使用队列按层序遍历树。这意味着从上到下,从左到右访问节点。 打印节点值:对于每个节点 如果节点为 null,则打印“null”。 如果节点不为 null,则打印其值。 步骤 2:将子节点添加到队列:打印当前节点后,将其左子节点和右子节点添加到队列。如果它们是 null,我们仍然会添加它们,以确保正确表示缺失的子节点。 `printTree` 函数将继续执行,直到所有节点都被处理,并将显示树的层序表示,这对于可视化非常有用。 步骤 3:后遍历清理(人工解释) 在按层级遍历完整个树后,打印的表示在末尾可能会包含额外的“null”值。这些“null”值通常代表树的最后一级中不存在的子节点,对于理解其结构不是必需的。为了清理输出 识别末尾的 Null 值:检查遍历过程中收集的值列表的最后一个节点。这些将是标记为“null”的节点。 移除冗余 Null 值:从列表末尾开始反向工作,删除连续的“null”值,直到遇到一个具有实际值的节点。 结果:这确保树的输出不包含不必要的占位符,使其更简洁易读。 步骤 4:格式化并打印最终输出 在从层序遍历中清理了不必要的末尾“null”值后,以清晰有序的格式呈现树结构,以便于可视化或调试。 合并值:使用清理后的节点值列表创建一个单一的字符串表示形式的树,并用逗号分隔。例如,[1,2,3,null,4]。 添加括号:将字符串放在方括号 ([]) 中,使其在视觉上与编码平台或讨论中的典型树表示一致。 输出树:打印或返回格式化的字符串。此最终表示提供了树结构的易于理解的概述,其中缺失的节点由“null”表示。 文件名:TreeNode.java 输出 Serialized Tree: 1,2,null,null,3,4,null,null,5,null,null, Deserialized Tree (Level-order): 1 2 3 null null 4 5 null null null null. 复杂度分析时间复杂度序列化和反序列化的时间复杂度均为 O(n),其中 n 是树中的节点数。序列化涉及访问每个节点一次,而反序列化在列表中处理每个节点一次以重构树,确保两者都是线性时间。 空间复杂度序列化的空间复杂度为 O(n),因为需要存储序列化字符串,其中 n 是节点数。反序列化需要 O(n) 的空间来存储包含节点值的列表,以及 O(h) 的空间用于递归栈,其中 h 是树的高度,因此总体为 O(n)。 下一个主题Java 中的 Pell 数 |
? 在 Java 中,将登录页面连接到数据库涉及多个过程:构建数据库、建立连接以及运行 SQL 查询。这是一个全面的指南,其中包含所有 Java 代码。Java 中的数据库连接 JDBC (Java 数据库连接) Java 数据库连接,简称...
5 分钟阅读
A 是一个访问修饰符。它可以分配给变量、方法、构造函数和类。它是最不受限制的访问修饰符类型。要点:公共访问修饰符在任何地方都可访问。因此,我们可以轻松地在类内部和外部访问公共...
阅读 3 分钟
? Java 是一种面向对象的编程语言,允许使用引用变量来处理对象及其数据。在 Java 中,对象在堆内存中动态创建,并使用引用变量来保存这些对象的内存地址。这种引用概念...
阅读 3 分钟
? Java 是一种用途广泛且功能强大的编程语言,由于其“一次编写,到处运行”的理念而广受欢迎。实现这一点的关键组件之一是 Java 运行时环境 (JRE)。在本节中,我们将深入探讨 JRE 的作用...
阅读 3 分钟
在本节中,我们将创建 Java 程序,以生成指定范围(0 到 n)内的二进制数。可以通过二叉树生成从 1 到 n 的二进制数。我们知道在树中,每个节点都有两个子节点...
阅读 3 分钟
Java 8 引入的 java.util.function 包包含 ToIntFunction 接口,该接口用于在语言中实现函数式编程。它表示一个接受 T 类型参数并输出整数值的函数。只有一个通用...
阅读 3 分钟
? Java 是一种广泛使用的编程语言,以其平台独立性而闻名,这得益于其架构中立的性质。“架构中立”一词是指 Java 能够在不修改的情况下在各种硬件和软件平台上运行。这一特性一直是 Java 普及和...
阅读 4 分钟
在本节中,我们将学习什么是 Pell 数,并创建 Java 程序来检查给定的数是否为 Pell 数。Pell 数程序经常在 Java 编码面试和学术中出现。Pell 数它是一系列或序列...
阅读 3 分钟
Java 静态类型与动态类型 Java 是一种强类型语言,它将变量、表达式和对象分类为静态类型。然而,Java 也通过使用其面向对象的特性来支持动态类型。在本节中,我们将探讨 Java 中的静态类型和动态类型概念...
5 分钟阅读
? 在 Java 中,包是 Java 类和接口的集合。当我们使用某个包的类时,需要导入定义这些类的特定包。该类使用包含包名的完全限定名称....
阅读 2 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India