在Java中对二进制树进行序列化和反序列化是最受欢迎的代码挑战之一,可以测试你的熟练程度。
序列化是将数据结构或对象转换为一个比特序列或字符串的过程。
然后,代表该对象的字符串可以存储在文本文件中,或通过流传输给需要该数据的其他网络。
反序列化是将比特序列转换回其原始对象的过程,这样它就可以被编程语言在其代码中使用。
下图说明了二进制树的序列化和反序列化过程:

Java中的序列化和反序列化图
(serialize-deserialize-binary-tree-java.png)
上图中的标记# ,用来表示null 值。它意味着该节点没有更多的子节点。
本教程将帮助你学习如何在Java中对二叉树进行序列化和反序列化。
但首先,让我们创建一个TreeNode ,这个类将用于创建二叉树。
在Java中创建二叉树类
下面的TreeNode 类是用来在Java中创建一个二叉树的:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
然后你可以在main() 方法中创建二叉树,如下图所示:
TreeNode root = new TreeNode(9);
root.left = new TreeNode(3);
root.right = new TreeNode(5);
root.right.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(7);
现在你可以创建一棵二叉树了,让我们来学习如何将二叉树对象序列化。
在Java中序列化一个二叉树
首先,为一个名为BinaryTreeCodec 或简称BTCodec 的Java类创建一个新文件。
在这个类中,创建一个名为serialize() 的新方法,返回一个String ,并接受一个TreeNode 对象:
class BTCodec {
String serialize(TreeNode root) {
}
}
为了序列化TreeNode 对象,你需要递归地调用serialize() 方法,将root.val 的值返回为字符串,并将它们串联起来。
当root 是null ,你需要返回# 符号作为null 的标记:
String serialize(TreeNode root) {
if (root == null) {
return "#";
}
return "" + root.val + "," + serialize(root.left) + "," + serialize(root.right);
}
你可以在你的Java项目的main() 方法中试用serialize() 方法:
public class Main {
public static void main(String[] args) {
TreeNode root = new TreeNode(9);
root.left = new TreeNode(3);
root.right = new TreeNode(5);
root.right.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(7);
BTCodec codec = new BTCodec();
String data = codec.serialize(root);
System.out.println(data);
}
}
上面的data 字符串的输出应该是这样的:
9,3,1,#,#,7,#,#,5,#,6,#,#
上面的序列化过程将从根部开始遍历二进制树的深度。
一旦到达最左边的节点的末端,该方法将开始遍历右边的子节点。这也被称为前序遍历方法。
现在你可以将Java中的二叉树序列化为String ,现在是时候学习如何将它反序列化为二叉树了。
在Java中对二叉树进行反序列化
与序列化过程类似,你可以在ArrayList 对象的帮助下将一个String 反序列化为二叉树。
回到BinaryTreeCodec 类中,你需要定义一个名为deserialize() 的新方法,该方法返回一个TreeNode ,并接受一个String 作为其参数:
TreeNode deserialize(String data) {}
首先,你需要检查data 字符串是否是null 。如果是,你可以返回一个null 的值。
当data 字符串不是null ,那么你可以继续将该字符串再次分割成一个ArrayList 。
之后,调用一个名为deserial() 的辅助函数,如下所示。接下来你将定义这个方法:
TreeNode deserialize(String data) {
if (data == null){
return null;
}
List<String> values = new ArrayList<>(Arrays.asList(data.split(",")));
return deserial(values);
}
上面的deserial() 方法将是一个你可以递归调用的方法,从给定的ArrayList 建立二叉树。
下面是deserial() 方法的代码:
private TreeNode deserial(List<String> values){
String val = values.remove(0);
if (val.equals("#")) return null;
TreeNode root = new TreeNode(Integer.parseInt(val));
root.left = deserial(values);
root.right = deserial(values);
return root;
}
首先,你使用remove() 方法来获取存储在ArrayList 中的第一个元素。
当值等于# ,你可以返回null ,因为这意味着树节点没有任何更多的值。
如果值不是null ,那么你就创建一个新的TreeNode 对象,并使用Integer.parseInt() 方法将String 值转换成int 。
然后,你递归地调用deserial() 方法,直到values 列表中的所有元素都被处理。
该方法将返回你所创建的TreeNode 的root 节点。
测试代码
现在,BinaryTreeCodec 类已经完成,你可以测试代码,如下所示:
public class Main {
public static void main(String[] args) {
TreeNode root = new TreeNode(9);
root.left = new TreeNode(3);
root.right = new TreeNode(5);
root.right.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(7);
BTCodec codec = new BTCodec();
String data = codec.serialize(root);
System.out.println(data);
TreeNode deserialized = codec.deserialize(data);
System.out.println(deserialized.val);
System.out.println(deserialized.left.val);
System.out.println(deserialized.right.val);
System.out.println(deserialized.right.right.val);
System.out.println(deserialized.left.left.val);
System.out.println(deserialized.left.right.val);
}
}
上述代码的输出将如下:
9,3,1,#,#,7,#,#,5,#,6,#,#
9
3
5
6
1
7
TreeNode 已经使用BinaryTreeCodec 类成功地进行了序列化和反序列化。
你可以在以下GitHub资源库中获得本教程的所有代码。
在本教程中,你已经学会了如何对二叉树进行序列化和反序列化,干得好!😉