描述
请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,可以根据层序遍历并特定标志空结点的方案序列化,也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。
假如一棵树共有 2 个结点, 其根结点为 1 ,根结点右子结点为 2 ,没有其他结点。按照上面第一种说法可以序列化为“1,#,2,#,#”,按照上面第二种说法可以序列化为“{0:1,2:2}”,按照上面第三种说法可以序列化为“1,2;2,1”,这三种序列化的结果都包含足以构建一棵与原二叉树完全相同的二叉树的信息。
不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。
思路
层次遍历
- 使用INF = 0x3f3f3f3f 作为无效值(当然也可以不使用数字,使用某个特殊字符进行表示,只要能在反序列时有所区分即可)
- 建立占位节点 emptyNode 用来代指空节点(emptyNode.val = INF)。
- "_"作为分隔符
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.Queue;
import java.util.LinkedList;
public class Solution {
int INF = 0x3f3f3f3f;
TreeNode emptyNode = new TreeNode(INF);
String LINE = "_";
String Serialize(TreeNode root) {
if(root == null) {
return null;
}
StringBuffer sb = new StringBuffer();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
sb.append(node.val + LINE);
if(node != emptyNode) {
queue.add(node.left != null ? node.left : emptyNode);
queue.add(node.right != null ? node.right : emptyNode);
}
}
return sb.toString();
}
TreeNode Deserialize(String str) {
if(str == null) {
return null;
}
// 根据分隔符进行分割
String[] strArr = str.split(LINE);
int n = strArr.length;
TreeNode root = new TreeNode(Integer.valueOf(strArr[0]));
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
//注意不要数组越界
for (int i = 1; i<n-1; i+=2) {
TreeNode node = queue.poll();
int left = Integer.valueOf(strArr[i]);
if (left != INF) {
TreeNode leftNode = new TreeNode(left);
node.left = leftNode;
queue.add(leftNode);
}
int right = Integer.valueOf(strArr[i+1]);
if (right != INF) {
TreeNode rightNode = new TreeNode(right);
node.right = rightNode;
queue.add(rightNode);
}
}
return root;
}
}