题目
请实现两个函数,分别用来序列化和反序列化二叉树。
分析
我们清楚可以通过前序遍历序列和中序遍历序列创造出一棵二叉树。因此,我们可以先把一棵二叉树序列化成一个前序遍历序列和一个中序遍历序列,然后在反序列化时通过这两种序列还原二叉树。
但是,该方法有两个缺点:
- 该方法要求二叉树中不能有数值重复的节点
- 只有当两个序列中所有数据读出来才能开始序列化。如果两个遍历序列的数据是从一个流里读出来的,那么可能需要等待较长时间。
实际上,如果二叉树的序列化是从根节点开始的,那么相应的反序列化在根节点的数值读出来的时候就可以开始了。因此,我们可以根据前序遍历的顺序来序列化二叉树,因为前序遍历是从根节点开始的。在遍历二叉树碰到空指针时,这些空指针序列化为一个特殊的字符(如$)。另外,节点的数值之间要用一个特殊字符 (如,) 隔开。
反序列化二叉树也按照前序遍历思路。
放码
import com.lun.util.BinaryTree.TreeNode;public class SerializeBinaryTree {public void serialize(TreeNode node, StringBuilder result) {if(node == null) {result.append("$,");return;}result.append(node.val + ",");serialize(node.left, result);serialize(node.right, result);}public TreeNode deserialize(StringBuilder sb) {Integer number = readNum(sb);TreeNode node = null;if(number != null) {node = new TreeNode(number);node.left = deserialize(sb);node.right = deserialize(sb);}return node;}public Integer readNum(StringBuilder sb) {int firstCommaIndex = sb.indexOf(",");String numStr = sb.substring(0, firstCommaIndex);Integer result = null;if(!numStr.equals("$")) {result = Integer.valueOf(numStr);}try {sb.delete(0, firstCommaIndex + 1);}catch (Exception e) {// do nothing}return result;}}
测试
import static org.junit.Assert.*;import org.junit.Test;import com.lun.util.BinaryTree;
import com.lun.util.BinaryTree.TreeNode;public class SerializeBinaryTreeTest {@Testpublic void testSerialize() {SerializeBinaryTree sbt = new SerializeBinaryTree();StringBuilder result = new StringBuilder("");TreeNode root = makeATree();sbt.serialize(root, result);assertEquals("1,2,4,$,$,$,3,5,$,$,6,$,$,", result.toString());}@Testpublic void testReadNum() {SerializeBinaryTree sbt = new SerializeBinaryTree();StringBuilder sb = new StringBuilder("1,2,4,$,$,$,3,5,$,$,6,$,$,");assertEquals(1, sbt.readNum(sb).intValue());assertEquals("2,4,$,$,$,3,5,$,$,6,$,$,", sb.toString());assertEquals(2, sbt.readNum(sb).intValue());assertEquals("4,$,$,$,3,5,$,$,6,$,$,", sb.toString());assertEquals(4, sbt.readNum(sb).intValue());assertEquals("$,$,$,3,5,$,$,6,$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("$,$,3,5,$,$,6,$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("$,3,5,$,$,6,$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("3,5,$,$,6,$,$,", sb.toString());assertEquals(3, sbt.readNum(sb).intValue());assertEquals("5,$,$,6,$,$,", sb.toString());assertEquals(5, sbt.readNum(sb).intValue());assertEquals("$,$,6,$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("$,6,$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("6,$,$,", sb.toString());assertEquals(6, sbt.readNum(sb).intValue());assertEquals("$,$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("$,", sb.toString());assertNull(sbt.readNum(sb));assertEquals("", sb.toString());}@Testpublic void testDeserialize() {SerializeBinaryTree sbt = new SerializeBinaryTree();TreeNode root = null;TreeNode root2 = makeATree();StringBuilder sb = new StringBuilder("");sbt.serialize(root2, sb);root = sbt.deserialize(sb);assertTrue(BinaryTree.equals(root, root2));}private TreeNode makeATree() {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.right.left = new TreeNode(5);root.right.right = new TreeNode(6);return root;}}