二叉树的序列化和反序列化

http://blog.csdn.net/qq_27703417/article/details/70958692

先序遍历二叉树,如果遇到空节点,就在str的末尾加上“#!”,“#”表示这个节点为空,节点值不存在,当然你也可以用其他的特殊字符,“!”表示一个值的结束。如果遇到不为空的节点,假设节点值为3,就在str的末尾加上“3!”。现在请你实现树的先序序列化。

先序遍历

  1. import java.util.*;
  2. //使用递归先序遍历对二叉树进行序列化
  3. public class TreeToString {
  4. public String toString(TreeNode root) {
  5. //注意:Java中String是不可改变的,不能进行引用传递,改为使用StringBuffer
  6. StringBuilder res=new StringBuilder("");
  7. //调用递归方法完成二叉树遍历序列化
  8. this.preOrder(root,res);
  9. //返回结果
  10. return res.toString();
  11. }
  12. //递归方法,用来先序遍历二叉树同时将其序列化为字符串
  13. private void preOrder(TreeNode root, StringBuilder str){
  14. //递归结束的边界条件
  15. if(root==null){
  16. str.append("#!");
  17. return;
  18. }
  19. //先遍历根结点
  20. str.append(root.val+"!");
  21. //遍历左子树
  22. this.preOrder(root.left,str);
  23. //遍历右子树
  24. this.preOrder(root.right,str);
  25. }
  26. }

反序列化

所谓反序列化是根据一个字符串重新建立一棵二叉树,反序列化是序列化的逆过程,对于一个字符串,首先按照分隔符!将其分割为字符串数组,每个字符串元素代表一个结点,然后开始重建二叉树。由于每个结点再字符串中只保留了一个val值,因此需要根据结点的值val重新构建TreeNode结点对象,并且为这个结点对象的left和right进行赋值。

反序列化比序列化要难,其实代码实现是类似的,只也是使用递归,只是这时候是反向的递归,比较抽象,要逐渐理解。已知一个用!分割的字符串是某个二叉树按照先序遍历顺序序列化得到的字符串,将其反序列化建立一棵二叉树,注意,要进行反序列化必须要知道这个字符串是按照什么顺序序列化得到的,只有按照相同的遍历顺序对其进行反序列化才能恢复正确的二叉树。一般使用先序遍历顺序进行序列化和反序列化。在反序列化时,首先得到一个字符串数组strs[]表示字符串序列拆分得到的字符串数组,数组的每个元素字符串对应一个结点的值,可以是3!或者是#!,分别表示一个非空的结点或者是空结点。即要求实现的功能是:根据给定的字符串数组strs[],重建一棵二叉树并返回这棵二叉树的头结点root。

分析:对于字符串数组strs[],第1个元素是根结点,第2个元素是左结点,第3个元素可能是第2个结点的左结点或者是第1个结点的右结点,要根据第2个结点是否为null来确定,即对于strs[],里面的元素必然是按照:根结点à左结点à左结点à左结点(null)à右结点à左结点à左结点(null)à右结点的顺序来排列的,因此总是先递归地恢复建立左结点,当遇到null时,说明这条路径结束了,node结点的left为null,应该返回到node结点并开始恢复一个右结点,此时相当于一个新的重复的过程,可以把这个右结点当做root开始新的递归过程。

即要求实现一个递归方法private TreeNode deSerialize(String[] strs);对于一个(或者部分)字符串数组,恢复一棵二叉树,并返回这棵二叉树的根结点。

逐个遍历数组strs[],当遇到“#”说明这是一个空结点,在这个根结点的后面不可能建立二叉树,于是相当于建立子树工作完成,返回根结点即返回null即可;如果遇到的是非空的字符串,例如“3”,表明这是一个非空的结点,首先建立这个结点TreeNode newNode=new TreeNode(3);但是此时仅仅恢复了一个结点,还要恢复它的子树,并且是先恢复左子树,再恢复右子树。如何恢复左子树?显然要根据数组strs[]的下一个元素开始的数组部分来恢复一棵二叉树,这就是这个递归函数的功能(根据一个或者部分字符串数组来建立一棵二叉树),于是调用自身这个递归函数即可,只是此时使用的字符串向后面移动了1个元素而已。

调用完这个函数后,就要认为结点③的左子树已经恢复完毕了,于是开始恢复结点③的右子树newNode.right;恢复右子树的过程还是一样的,也是相同的逻辑(根据一个或者部分字符串数组来建立一棵二叉树),只是此时恢复的二叉树连接到的不是newNode.left上面而是newNode.right上面,当调用完这个函数后,就认为结点newNode的右子树已经恢复完成了,于是整个newNode的val有了,left、right都有了值,于是整棵二叉树就建立了,此时根据函数功能的要求,要返回这棵建立起来的二叉树的根结点,于是返回newNode即可。

常识:没有构造方法时默认有参数为空的构造函数可以不写;当写有含参的构造方法时,如果不写参数为空的构造方法,就不能再使用TreeNode newNode=new TreeNode()这种构造方法,如果要用就必须显示地定义参数为空的构造方法。

  1. public class Solution {
  2. //已知由先序遍历得到的字符串str,将其恢复为一棵二叉树,并返回根结点
  3. TreeNode Deserialize(String str) {
  4. //特殊输入
  5. if(str==null||str.length()<=0) return null;
  6. //将字符串按照","拆分为数组
  7. String[] strs=str.split(",");
  8. //调用递归方法deSerializeCore()方法来实现重建二叉树的功能,返回根结点
  9. TreeNode root=this.deSerializeCore(strs);
  10. //注意返回结果
  11. return root;
  12. }
  13. //注意:这里关键是要设计一个成员变量index用于在每次递归调用时能够使用不同的字符串来建立根结点
  14. int index=0;
  15. //设计一个递归方法deSerializeCore用于使用strs[]数组的后面部分元素来建立一棵二叉树,并返回根结点
  16. //递归方法可以有返回值或者没有返回值,不影响使用,如果有返回值要注意接收
  17. private TreeNode deSerializeCore(String[] strs){
  18. if("#".equals(strs[index])){
  19. //如果遇到的是#表示空节点,不再建立子树,这个结点null就是子树的根结点返回
  20. //千万注意,返回前要将index向下移动,之后使用的是strs[]中后面部分的元素
  21. index++;
  22. return null;
  23. }else{
  24. //如果不为空结点,则先恢复这个结点
  25. TreeNode newNode=new TreeNode(0);
  26. newNode.val=Integer.parseInt(strs[index]);
  27. //千万注意在递归调用之前(使用了一个元素建立结点之后),要将index向后移动1位
  28. index++;
  29. //恢复左子树
  30. newNode.left=this.deSerializeCore(strs);
  31. //恢复右子树
  32. newNode.right=this.deSerializeCore(strs);
  33. //建立二叉树完成,返回根结点
  34. return newNode;
  35. }
  36. }
  37. }
时间: 2024-10-21 11:20:55

二叉树的序列化和反序列化的相关文章

lintcode 中等题:binary tree serialization 二叉树的序列化和反序列化

题目 二叉树的序列化和反序列化 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”. 如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构. 样例 给出一个测试数据样例, 二叉树{3,9,20,#,#,15,7},表示如下的树结构: 3 / 9 20 / 15 7 我们的数据是进行BFS遍历得到的.当你测试结果wrong answer时,你可以作为输

Leetcode 297.二叉树的序列化和反序列化

二叉树地序列化和反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个算法来实现二叉树的序列化与反序列化.这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构. 示例:  你可以将以下二叉树: 序列化为 "[1,2,3,null,null,4,5]" 提示: 这与 Le

二叉树的序列化和反序列化(先序,按层序列化),包含递归图

目录 二叉树的序列化与反序列化 按层序列化 使用#!和!的原因: 二叉树的序列化与反序列化 序列化:将对象的状态信息转换为可以存储或传输的形式的过程 二叉树的序列化:就是将二叉树转换成字符串 二叉树的反序列化:通过字符串还原一棵二叉树,返回树的头节点. 先序序列化二叉树 上面这棵树的先序序列化结果为5!3!2!1!#!#!#!4!#!#!8!7!6!#!#!#!10!9!#!#!11!#!#! 从上图中我们可以看出在节点为空的位置使用"#!"来代替,每个节点后的数值都添加一个"

二叉树的序列化与反序列化

一个二叉树被序列化为数组,如何反序列化,也就是如何从序列化好的一个数组恢复成二叉树? 在上一篇文章中讲述了如何将一个有序数组创建成一个二叉搜索树,那么如果将将一个儿茶搜索树序列化为一个有序数组,然后按照上面的方法在反序列化即可.对二叉搜索树进行中序遍历即可得到一个有序的数组,那么上篇文章已经完成了对二叉搜索树的序列化和反序列化.同时如果想将二叉搜索树的序列化和反序列化的结果通过文件读取,也是同样的道理. 设计一个算法,将一棵二叉搜索树(Binary Search Tree,BST)保存到文件中,

二叉树的序列化、反序列化

一. 使用先序遍历的方式 [1]中的方式是采用设定#的方式,当访问读取了#时候,创建null,返回. 二.二叉搜索树的序列化 二叉搜索树具有的有序的性质,可以利用这个性质来递归的反序列化BST 对当前节点要处理的数据的范围设定一个边界,当读取的值是在这个范围里面的时候,则进行node的创建,否则创建NULL节点,对于值的node创建需要递归到上一层递归,寻找新的方案,如果还是不行,以此类推. [1] http://blog.csdn.net/pi9nc/article/details/97016

树(7)-----二叉树的序列化和反序列化

1.序列化:层次遍历[用字符串来存储] 2.反序列化:用队列存已经建立的节点,从序列化后的字符串列表取数来建立树 def serialize(self, root): """Encodes a tree to a single string. :type root: TreeNode :rtype: str """ if not root: return "" prev,strres=[root],"" w

leetcode 297二叉树的序列化与反序列化

采用层序遍历的顺序,储存每一层的值,不存在的或者NULL值用#代替,每个位置以'/'结束 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Codec { public: // Encodes

Leetcode 297. 二叉树的序列化与反序列化

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ #include <stringstream> class Codec { public: void serialize(TreeNode* root,

序列化与反序列化二叉树

2018-06-16 18:53:36 序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程.反序列化顾名思义就是通过信息流对对象进行重建的过程. 一般来说序列化和反序列化有如下的作用: 1.以某种存储形式使自定义对象持久化: 2.将对象从一个地方传递到另一个地方. 3.使程序更具维护性. 本篇文章主要讨论的是二叉树的序列化和反序列化,分别讨论了普通二叉树和二叉搜索树的情况. 一.普通二叉树的序列化和反序列化 问题描述: 问题求解: 序列化和反序列化二叉树本质上