《剑指Offer》37:序列化二叉树

题目

请实现两个函数,分别用来序列化和反序列化二叉树。

分析

我们清楚可以通过前序遍历序列和中序遍历序列创造出一棵二叉树。因此,我们可以先把一棵二叉树序列化成一个前序遍历序列和一个中序遍历序列,然后在反序列化时通过这两种序列还原二叉树。

但是,该方法有两个缺点:

  1. 该方法要求二叉树中不能有数值重复的节点
  2. 只有当两个序列中所有数据读出来才能开始序列化。如果两个遍历序列的数据是从一个流里读出来的,那么可能需要等待较长时间。

实际上,如果二叉树的序列化是从根节点开始的,那么相应的反序列化在根节点的数值读出来的时候就可以开始了。因此,我们可以根据前序遍历的顺序来序列化二叉树,因为前序遍历是从根节点开始的。在遍历二叉树碰到空指针时,这些空指针序列化为一个特殊的字符(如$)。另外,节点的数值之间要用一个特殊字符 (如,) 隔开。

反序列化二叉树也按照前序遍历思路。

放码

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 {

	@Test
	public 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());
	}
	
	@Test
	public 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());
	}
	
	@Test
	public 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;
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值