序列化二叉树
序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树。例如:

序列化为 "[1,2,3,null,null,4,5]"("[1,2,3,null,null,4,5,null,null,null,null]")
题目分析
返回结果分析
序列化
序列化二叉树返回的结果是字符串类型,但每次访问一个节点只能得到一个节点的结果,但是为了方便把null加入结果集的操作,这里就使用StringBuilder。
显然,遍历序列的结果与一般的二叉树层次遍历很相似,层次遍历得到的结果是[1 , 2 , 3 , 4 , 5],是没有null值的,所以可以借鉴层次遍历的思想,这里先回顾一下二叉树的层次遍历。
反序列化
有个关键的步骤是,如何从一个字符串中获取到每一个元素,首先使用subString把头和尾的 [ ]去掉,再使用split,官方文档的解释是这样的:


也就是说根据给定的正则表达式分割字符串,在这里这样用:
String[] elements = data.substring(1,data.length() - 1).split(",");
也就是说只要匹配到了‘ , ’就分割一个子字符串放进新的字符串数组中,拿到了每一个元素就好办了,后面也是相同的,只要判断然后对应创建就可以了
过程分析
层次遍历
层次遍历使用了一个队列,让根节点先入队,每出队一个节点,就把这个节点的数据放进结果集,并且把他的孩子入队(如果不为空),详细步骤如下:
| 辅助队列 | 1 | 1出队放入结果集 | 把1的孩子(2,3)入队 | 结果集 | 1 |
|---|---|---|---|---|---|
| 辅助队列 | 2 3 | 2出队放入结果集 | 2的孩子(null,null)不入队 | 结果集 | 1 2 |
| 辅助队列 | 3 | 3出队放入结果集 | 把3的孩子(4,5)入队 | 结果集 | 1 2 3 |
| 辅助队列 | 4 5 | 4出队放入结果集 | 4的孩子(null,null)不入队 | 结果集 | 1 2 3 4 |
| 辅助队列 | 5 | 5出队放入结果集 | 5的孩子(null,null)不入队 | 结果集 | 1 2 3 4 5 |
序列化
序列化其实就是一个带有null值的层次遍历(不是标准的,只是把叶子节点的null值加入结果集)如图:

序列化
把二叉树转换为遍历序列加强版的过程
思路
由上面的分析可以进行改进。在层次遍历中,条件是取出队列中的元素,并且放入结果集。
在序列化中,只需要把取出来的元素加上一层判断即可,如果这个节点不为空,则加入值,如果为空则加入null
| queue | 1 | 1加入结果集 | 把1的孩子(2,3)入队 | 结果集 | 1 |
|---|---|---|---|---|---|
| queue | 2 3 | 2加入结果集 | 把2的孩子(null,null)加入 | 结果集 | 1,2 |
| queue | 3 null null | 3加入结果集 | 把3的孩子(4,5)入队 | 结果集 | 1,2,3,null,null |
| queue | 4 5 | 4加入结果集 | 把4的孩子(null,null)加入 | 结果集 | 1,2,3 ,null,null,4 |
| queue | 5 null null | 5加入结果集 | 把5的孩子(null,null)加入 | 结果集 | 1,2,3,null,null,4,5 |
| queue | null null null null | null加入结果集 | \ | 结果集 | 1,2,3,null,null,4,5,null,null,null,null |
代码实现
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
if (root == null)
return "[]";
else {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
sb.append("[");
while(!queue.isEmpty()){
TreeNode node = queue.poll();
if (node != null){
sb.append(node.val);
queue.offer(node.left);
queue.offer(node.right);
}
else
sb.append("null");
sb.append(",");
}
sb.append("]");
sb.deleteCharAt(sb.length() - 2);
}
return sb.toString();
}
反序列化
把遍历数组恢复为二叉树的过程
思路
利用好[无论数组中哪一位加入了树中,index总是会向后移动一位]这个特点,就好了
代码实现
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if ("[]".equals(data))
return null;
String[] elements = data.substring(1,data.length() - 1).split(",");
Queue<TreeNode> queue = new LinkedList<>();
int index = 1;
TreeNode root = new TreeNode(Integer.parseInt(elements[0]));
queue.offer(root);
while (!queue.isEmpty()){
TreeNode node = queue.poll();
if (!"null".equals(elements[index])){
node.left = new TreeNode(Integer.parseInt(elements[index]));
queue.offer(node.left);
}
index++;
if (!"null".equals(elements[index])){
node.right = new TreeNode(Integer.parseInt(elements[index]));
queue.offer(node.right);
}
index++;
}
return root;
}
测试用例
public static void main(String[] args) {
//定义一棵树
TreeNode e = new TreeNode(5,null,null);
TreeNode d = new TreeNode(4,null,null);
TreeNode c = new TreeNode(3,d,e);
TreeNode b = new TreeNode(2,null,null);
TreeNode a = new TreeNode(1,b,c);
//定义一个遍历序列
String data = "[1,2,3,null,null,4,5,null,null,null,null]";
//创建实例
serNDeser serial = new serNDeser();
//查看二叉树序列化得到的结果
System.out.println(serial.serialize(a));
//查看序列化结果是否与测试用例的字符串等值
System.out.println(serial.serialize(a).equals(data));
//查看通过把测试用例反序列化得到的结果进行序列化,查看(序列化函数和反序列化函数是否是可逆的)
System.out.println(serial.serialize(serial.deserialize(data)));
}


浙公网安备 33010602011771号