vlambda博客
学习文章列表

二叉树的序列化&反序列化

一. 题目:


    二叉树被记录成文件的过程叫作二叉树的序列化,通过文件内容重建原来二叉树的过程叫作二叉树的反序列化。

    给定一棵二叉树的头节点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. 运行效果图:



如果不懂怎么打印二叉树的小伙伴请看这篇:



总结:二叉树的序列化&反序列化听起来挺高大上的,搞通原理后,也就是那样了,还是很清晰明了的,实现起来也很简单。