二叉树的序列化与反序列化
PS:leetCode的题多加了一点限制,就是要求不能使用全局或者静态变量存储状态。
分析:将二叉树序列化成一个字符串存储,然后将该字符串反序列化成一个二叉树。关于二叉树的操作,我们很容易的就想到了二叉树的遍历,包括层次遍历和前、中、后序遍历。因为要反序列化二叉树,所以肯定要在遍历过程中记录null
节点,我们可以用一个特殊标记表示null
节点.
做法1:利用前序遍历
public int index = -1;
String Serialize(TreeNode root) {
StringBuffer sb = new StringBuffer();
if(root == null){
sb.append("#,");
return sb.toString();
}
sb.append(root.val + ",");
sb.append(Serialize(root.left));
sb.append(Serialize(root.right));
return sb.toString();
}
TreeNode Deserialize(String str) {
index++;
int len = str.length();
if(index >= len){
return null;
}
String[] strr = str.split(",");
TreeNode node = null;
if(!strr[index].equals("#")){
node = new TreeNode(Integer.valueOf(strr[index]));
node.left = Deserialize(str);
node.right = Deserialize(str);
}
return node;
}
做法1有几个缺点:
index是全局变量,违反了leetcode上原题的规定
因为用了递归,所以比较损耗性能。leetcode上给的测试用例比较大,所以相同的代码在牛客网上可以通过,在leetcode上就会超时。做法2:利用层次遍历
String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(root != null)
queue.add(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
if(node != null){
queue.offer(node.left);
queue.offer(node.right);
sb.append(node.val + ",");
}else{
sb.append("#" + ",");
}
}
if(sb.length() != 0)
sb.deleteCharAt(sb.length()-1);
return sb.toString();
}
TreeNode deserialize(String str) {
TreeNode head = null;
if(str == null || str.length() == 0)
return head;
String[] nodes = str.split(",");
TreeNode[] treeNodes = new TreeNode[nodes.length];
for(int i=0; i<nodes.length; i++){
if(!nodes[i].equals("#"))
treeNodes[i] = new TreeNode(Integer.valueOf(nodes[i]));
}
for(int i=0, j=1; j<treeNodes.length; i++){
if(treeNodes[i] != null){
treeNodes[i].left = treeNodes[j++];
treeNodes[i].right = treeNodes[j++];
}
}
return treeNodes[0];
}
很明显利用层次遍历的做法要更快一些,不用递归。
PS:利用后序遍历也可以实现,还有一种方法就是前序和中序、后序和中序都可以唯一确定一棵二叉树,所以我们在序列化的时候,可以前中和后中遍历,然后进行反序列化。
利用前序遍历和中序遍历重建二叉树,pre代表前序遍历,in代表中序遍历。
public static TreeNode reconstruct(int[] pre, int[] in, int startpre, int endpre, int startin, int endin) {
if(startpre > endpre || startin > endin) {
return null;
}
TreeNode root = new TreeNode(pre[startpre]);
for(int i = startin; i <= endin; i++) {
if(pre[startpre] == in[i]) {
root.left = help(pre,in,startpre+1,startpre+i-startin,startin,i-1);
root.right = help(pre,in,startpre+i-startin+1,endpre,i+1,endin);
}
}
return root;
}