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

不念不忘少年蓝@ 2024-04-18 17:11 167阅读 0赞

为了方便自己测试二叉树相关的代码,需要根据层序遍历快速反序列化一颗用于测试的二叉树,这样可以很方便的写测试用例。

因此简单梳理一下基于层序遍历的二叉树的序列化问题。

LintCode地址:https://www.lintcode.com/problem/serialize-and-deserialize-binary-tree/description

举例说明
在这里插入图片描述
在这里插入图片描述

序列化过程

与层次遍历相同的是:元素出现的次序与层序遍历相同;与层序遍历不同的是:增加的#,只要是非最后一层的节点,如果孩子为空,就需要用#表示。

在序列化的过程中,用ArrayList结构来存储层次遍历的TreeNode,将每层的节点存储到ArrayList当中,用StringBuilder来拼接序列化的结果。

ArrayList控制了层序遍历的方向: 在ArrayList上的指针不断后移,如果指向的节点不为空,将指向节点的左孩子和右孩子放入到ArrayList当中。而StringBuilder在遍历过程中不断添加节点值或者#构造结果。注意因为是序列化,当该节点的孩子节点为空,需要在String结果中添加#体现。

反序列化过程

字符串处理获取到字符串数组,根据字符串数组构建二叉树。我们可以观测一个非常使用的规律:对于不为#的节点,所有节点的左右孩子节点都依次排在list当中。
在这里插入图片描述
所以,我们可以设定父节点指针index,设定当前节点指针。当前节点指针构造节点之后,作为左节点或者有节点挂载在index指向的父节点上。当index的左、右孩子都处理之后则index后移,那么可以设置一个isLeftChild的标识位,如果当前是isLeftChild则当前节点是父节点的左孩子,反之则为右孩子。每次对右孩子处理完之后index指针就需要后移。

换句话说,要注意控制父节点指针index的移动时机,还需要确定当前节点是父节点的左孩子还是右孩子。

  1. import org.junit.Test;
  2. import java.util.ArrayList;
  3. /**
  4. * @author wanglong
  5. * @brief
  6. * @date 2019-09-10 08:56
  7. */
  8. // Definition of TreeNode:
  9. public class SerializeAndDeserializeBinaryTree {
  10. class TreeNode {
  11. public int val;
  12. public TreeNode left, right;
  13. public TreeNode(int val) {
  14. this.val = val;
  15. this.left = this.right = null;
  16. }
  17. }
  18. /**
  19. * This method will be invoked first, you should design your own algorithm
  20. * to serialize a binary tree which denote by a root node to a string which
  21. * can be easily deserialized by your own "deserialize" method later.
  22. */
  23. public String serialize(TreeNode root) {
  24. // write your code here
  25. if(root == null)
  26. return new String("{}");
  27. ArrayList<TreeNode> list = new ArrayList<>();
  28. list.add(root);
  29. for(int i = 0; i < list.size(); i ++){
  30. TreeNode curNode = list.get(i);
  31. if(curNode != null){
  32. list.add(curNode.left);
  33. list.add(curNode.right);
  34. }
  35. }
  36. while(list.get(list.size() - 1) == null)
  37. list.remove(list.size() - 1);
  38. StringBuilder sb = new StringBuilder("{");
  39. sb.append(list.get(0).val);
  40. for(int i = 1; i < list.size(); i ++){
  41. if(list.get(i) != null){
  42. sb.append(",");
  43. sb.append(list.get(i).val);
  44. }else{
  45. sb.append(",#");
  46. }
  47. }
  48. sb.append("}");
  49. return sb.toString();
  50. }
  51. /**
  52. * This method will be invoked second, the argument data is what exactly
  53. * you serialized at method "serialize", that means the data is not given by
  54. * system, it's given by your own serialize method. So the format of data is
  55. * designed by yourself, and deserialize it here as you serialize it in
  56. * "serialize" method.
  57. */
  58. public TreeNode deserialize(String data) {
  59. // write your code here
  60. if(data ==null || data.equals("{}") || data.length() == 0)
  61. return null;
  62. data = data.substring(1, data.length() - 1);
  63. String[] strs = data.split(",");
  64. ArrayList<TreeNode> nodeList = new ArrayList<>();
  65. TreeNode root = new TreeNode(Integer.parseInt(strs[0]));
  66. nodeList.add(root);
  67. boolean isLeftChild = true;
  68. int index = 0;
  69. for(int i = 1; i < strs.length; i ++){
  70. if(!strs[i].equals("#")){
  71. TreeNode curNode = new TreeNode(Integer.parseInt(strs[i]));
  72. if(isLeftChild)
  73. nodeList.get(index).left = curNode;
  74. else
  75. nodeList.get(index).right = curNode;
  76. nodeList.add(curNode);
  77. }
  78. if(!isLeftChild) //index计数后移(#和非空节点都需要进行)
  79. index ++;
  80. isLeftChild = !isLeftChild; //左右子节点替换(#和非空节点都需要进行)
  81. }
  82. return root;
  83. }
  84. @Test
  85. public void test(){
  86. //test case
  87. System.out.println(deserialize(new String("{3,9,20,#,#,15,7}")));
  88. }
  89. }

发表评论

表情:
评论列表 (有 0 条评论,167人围观)

还没有评论,来说两句吧...

相关阅读

    相关 序列/序列

    二叉树被记录成文件的过程,为二叉树的序列化 通过文件重新建立原来的二叉树的过程,为二叉树的反序列化 设计方案并实现。 (已知结点类型为32位整型) 思路:先序遍历实现。