二叉树的序列化&反序列化
一. 题目:
二叉树被记录成文件的过程叫作二叉树的序列化,通过文件内容重建原来二叉树的过程叫作二叉树的反序列化。
给定一棵二叉树的头节点head,并已知二叉树节点值的类型为32位整型。
二. 解题思路:
通过先序遍历实现序列化和反序列化:
先介绍先序遍历下的序列化过程,首先假设序列化的结果字符串为str,初始时str=""。
先序遍历二叉树,如果遇到null节点,就在str的末尾加上"#!","#"表示这个节点为空, 节点值不存在,”!”表示一个值的结束;
如果遇到不为空的节点,假设节点值为3,就在str的末尾加上"3!"。
比如图一所示的二叉树:
根据上图所示,可以得到先序遍历序列化,最后的结果字符串str为:12!3!#!#!#!。
为什么在每一个节点值的后面都要加上"!"呢?因为如果不标记一个值的结束,最后产生的结果会有歧义,如图二所示:
如果不在一个值结束时加入特殊字符,那么图一和图二的先序遍历序列化结果都是123###。也就是说,生成的字符串并不代表唯一的树。
三. 代码实现:
1. 序列化&反序列化:
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
// 序列化
public static String SerializeByPre(Node head) {
// 判断树是否为空
if (head == null) {
return "#!";
}
String res = head.value + "!";
res += SerializeByPre(head.left);
res += SerializeByPre(head.right);
return res;
}
// 解析字符串
public static Node reconByPre(String preStr) {
// 解析字符串
String[] split = preStr.split("!");
Queue<String> queue = new LinkedList<>();
// 把解析后的字符串放入到队列中
for (int i = 0; i != split.length; i++) {
queue.offer(split[i]);
}
return reconPreOrder(queue);
}
// 反序列化
private static Node reconPreOrder(Queue<String> queue) {
// 开始反序列化
String value = queue.poll();
// 判空
if (value.equals("#")) {
return null;
}
// 构建二叉树
Node head = new Node(Integer.valueOf(value));
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}
2. 打印输出序列化&反序列化:
// 这里打印二叉树使用的方法,就是上一篇文章:直观打印二叉树
public static void printTree(Node head) {
System.out.println("Binary Tree:" + "\n");
printInOrder(head, 0, "H", 10);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
String res = SerializeByPre(head);
System.out.println("序列化结果: " + res);
System.out.println("\n" + "反序列化结果: ");
Node head1 = reconByPre(res);
printTree(head1);
}
3. 运行效果图:
如果不懂怎么打印二叉树的小伙伴请看这篇:
总结:二叉树的序列化&反序列化听起来挺高大上的,搞通原理后,也就是那样了,还是很清晰明了的,实现起来也很简单。