剑-二叉树序列化与反序列化(三种解法)

假设有一个二叉树

    _30_
   /    \   
  10    20
 /     /  \
50    45  35

解法一:

前序遍历二叉树,空节点处插入#。如图

    _30_
   /    \   
  10    20
 /  \   /  \
50   # 45  35
/\     /\   /\ 
# #   #  # #  #
序列为:30,10,50,#,#,#,20,45,#,#,35,#,#

反序列化时只需要按照前序遍历的顺序,从序列中取节点,生成二叉树即可。

//序列化
public String Serialize(TreeNode root) {
	StringBuffer result = new StringBuffer();
	Serialize2(root, result);
	result.deleteCharAt(result.length() - 1);
	return result.toString();
}

private void Serialize2(TreeNode root, StringBuffer result) {
	if (root == null) {
		result.append('#');
		result.append(',');
		return;
	}

	result.append(root.val);
	result.append(',');
	Serialize2(root.left, result);
	Serialize2(root.right, result);

}
//反序列化
public TreeNode Deserialize(String str) {
		String[] res = str.split(",");
		TreeNode root = Deserialize2(res);

		return root;
	}

//代表当前序列序号,为全局变量
int i = 0;
private TreeNode Deserialize2(String[] res) {
	if (res[i].equals("#")) {
		i++;
		return null;
	}
	TreeNode root = new TreeNode(Integer.valueOf(res[i]));
	i++;
	root.left = Deserialize2(res);
	root.right = Deserialize2(res);
	return root;
}


解法二:

利用队列,层次遍历二叉树生成序列。填充#后图与解法一相同:

    _30_
   /    \   
  10    20
 /  \   /  \
50   # 45  35
/\     /\   /\ 
# #   #  # #  #

序列为:30,10,20,50,#,45,35,#,#,#,#,#,#

反序列化时只需要,建立队列按照层次遍历的顺序,从序列中取节点,生成二叉树。

//序列化
public String Serialize(TreeNode root) {
		if(root == null) return null;  
		StringBuffer result = new StringBuffer();
		Queue<TreeNode> queue = new LinkedList<>();
		queue.add(root);

		while (!queue.isEmpty()) {
			TreeNode tmp = queue.poll();
			if (tmp == null) {
				result.append("#,");
			} else {
				result.append(tmp.val + ",");
				queue.add(tmp.left);
				queue.add(tmp.right);
			}

		}

		result.deleteCharAt(result.length() - 1);
		return result.toString();
	}


//反序列化
public static TreeNode Deserialize(String str) {
		if (str == null || str.length() == 0)
			return null;

		String[] seq = str.split(",");
		int index = 0;
		TreeNode root = new TreeNode(Integer.valueOf(seq[index++]));
		Queue<TreeNode> queue = new LinkedList<>();
		queue.add(root);

		while (!queue.isEmpty()) {

			TreeNode p = queue.poll();

			if (!seq[index].equals("#")) {
				TreeNode lc = new TreeNode(Integer.valueOf(seq[index]));
				p.left = lc;
				queue.add(lc);
			}
			index++;
			if (!seq[index].equals("#")) {
				TreeNode rc = new TreeNode(Integer.valueOf(seq[index]));
				p.right = rc;
				queue.add(rc);
			}
			index++;

		}
		return root;
	}


解法三:

层次遍历二叉树,将二叉树填充成完全二叉树。

     _30_
   /      \   
  10       20
 /  \     /  \
50   #    45  35
/\   /\   /\   /\ 
# # # #  #  # #  #
序列为:30,10,20,50,#,45,35,#,#,#,#,#,#,#,#

反序列化时,利用完全二叉树性质。n号节点的左孩子为2*n+1,右孩子为2*n+2.

//序列化
public String Serialize2(TreeNode root) {
	        if(root == null){
	            return null;
	        }
	        StringBuffer sb = new StringBuffer();
	        Queue<TreeNode> queue = new LinkedList<>();
		//用于记录非空节点的个数
	        int valNum = 1;
	        queue.add(root);
	        
	        while(!queue.isEmpty()){
	        	TreeNode tmp = queue.poll();
	        	if(tmp != null){
	        		valNum--;
	        		sb.append(tmp.val + ",");
	        		queue.add(tmp.left);
	        		if(tmp.left != null) valNum++;
	        		queue.add(tmp.right);
	        		if(tmp.right != null) valNum++;
	        	}else{
	        		sb.append("#,");
			        //当后续队列中仍有非空节点,则需要其左右孩子继续填充#
	        		if(valNum > 0){
	        			queue.add(null);
	        			queue.add(null);
	        		}
	        	}
	        }
	        
	        sb.deleteCharAt(sb.length()-1);
	        return sb.toString();
	    }

//反序列化
public TreeNode Deserialize(String str) {
    if(str == null || str.length() == 0){
        return null;
    }
    return Deserialize(str.split(","), 0);
}

public TreeNode Deserialize(String[] strings, int index){ 
  TreeNode tmp = null;
  if(index < strings.length && !strings[index].equals("#")){
	  if(strings[index] != null){
		  tmp = new TreeNode(Integer.valueOf(strings[index]));
		  tmp.left = Deserialize(strings, index * 2 + 1);
		  tmp.right = Deserialize(strings, index * 2 + 2);
	  }
  }
  return tmp;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值