Binary Tree Serialization

Question

  1. Design an algorithm and write code to serialize and deserialize a binary tree.
  2. Writing the tree to a file is called 'serialization'
  3. and reading back from the file to reconstruct
  4. the exact same binary tree is 'deserialization'.
  5. There is no limit of how you deserialize or serialize a binary tree,
  6. you only need to make sure you can serialize a binary tree to a string
  7. and deserialize this string to the original structure.
  8. Have you met this question in a real interview? Yes
  9. Example
  10. An example of testdata: Binary tree {3,9,20,#,#,15,7},
  11. denote the following structure:
  12. 3
  13. / \
  14. 9 20
  15. / \
  16. 15 7
  17. Our data serialization use bfs traversal.
  18. This is just for when you got wrong answer and want to debug the input.
  19. You can use other method to do serializaiton and deserialization.

题解

根据之前由前序,中序,后序遍历恢复二叉树的经验,确定根节点的位置十分重要(但是这里可能有重复元素,故和之前的题目不太一样)。能直接确定根节点的有前序遍历和广度优先搜索,其中较为简洁的为前序遍历。序列化较为简单,但是反序列化的实现不太容易。需要借助字符串解析工具。

Python

  1. """
  2. Definition of TreeNode:
  3. class TreeNode:
  4. def __init__(self, val):
  5. self.val = val
  6. self.left, self.right = None, None
  7. """
  8. """
  9. Definition of TreeNode:
  10. class TreeNode:
  11. def __init__(self, val):
  12. self.val = val
  13. self.left, self.right = None, None
  14. """
  15. class Solution0:
  16. '''
  17. @param root: An object of TreeNode, denote the root of the binary tree.
  18. This method will be invoked first, you should design your own algorithm
  19. to serialize a binary tree which denote by a root node to a string which
  20. can be easily deserialized by your own "deserialize" method later.
  21. '''
  22. def serialize(self, root):
  23. if not root:
  24. return ''
  25. def post_order(root):
  26. if root:
  27. post_order(root.left)
  28. post_order(root.right)
  29. ret[0] += str(root.val) + ','
  30. else:
  31. ret[0] += '#,'
  32. ret = ['']
  33. post_order(root)
  34. return ret[0][:-1] # remove last ,
  35. '''
  36. @param data: A string serialized by your serialize method.
  37. This method will be invoked second, the argument data is what exactly
  38. you serialized at method "serialize", that means the data is not given by
  39. system, it's given by your own serialize method. So the format of data is
  40. designed by yourself, and deserialize it here as you serialize it in
  41. "serialize" method.
  42. '''
  43. def deserialize(self, data):
  44. if not data:
  45. return
  46. nodes = data.split(',')
  47. def post_order(nodes):
  48. if nodes[-1] == '#':
  49. nodes.pop()
  50. return None
  51. root = TreeNode(int(nodes.pop()))
  52. root.right = post_order(nodes)
  53. root.left = post_order(nodes)
  54. return root
  55. return post_order(nodes)
  56. class Solution1:
  57. '''
  58. @param root: An object of TreeNode, denote the root of the binary tree.
  59. This method will be invoked first, you should design your own algorithm
  60. to serialize a binary tree which denote by a root node to a string which
  61. can be easily deserialized by your own "deserialize" method later.
  62. '''
  63. def serialize(self, root):
  64. if not root:
  65. return ''
  66. def pre_order(root):
  67. if root:
  68. ret[0] += str(root.val) + ','
  69. pre_order(root.left)
  70. pre_order(root.right)
  71. else:
  72. ret[0] += '#,'
  73. ret = ['']
  74. pre_order(root)
  75. return ret[0][:-1] # remove last ,
  76. '''
  77. @param data: A string serialized by your serialize method.
  78. This method will be invoked second, the argument data is what exactly
  79. you serialized at method "serialize", that means the data is not given by
  80. system, it's given by your own serialize method. So the format of data is
  81. designed by yourself, and deserialize it here as you serialize it in
  82. "serialize" method.
  83. '''
  84. def deserialize(self, data):
  85. if not data:
  86. return
  87. nodes = data.split(',')
  88. self.i = 0
  89. def pre_order(nodes):
  90. if nodes[self.i] == '#':
  91. return None
  92. root = TreeNode(int(nodes[self.i]))
  93. self.i += 1
  94. root.left = pre_order(nodes)
  95. self.i += 1
  96. root.right = pre_order(nodes)
  97. return root
  98. return pre_order(nodes)
  99. import collections
  100. class Solution2:
  101. '''
  102. @param root: An object of TreeNode, denote the root of the binary tree.
  103. This method will be invoked first, you should design your own algorithm
  104. to serialize a binary tree which denote by a root node to a string which
  105. can be easily deserialized by your own "deserialize" method later.
  106. '''
  107. def serialize(self, root):
  108. if not root:
  109. return
  110. ret = []
  111. queue = collections.deque()
  112. queue.append(root)
  113. while queue:
  114. node = queue.popleft()
  115. if node:
  116. queue.append(node.left)
  117. queue.append(node.right)
  118. ret.append(str(node.val))
  119. else:
  120. ret.append('#')
  121. return ','.join(ret)
  122. '''
  123. @param data: A string serialized by your serialize method.
  124. This method will be invoked second, the argument data is what exactly
  125. you serialized at method "serialize", that means the data is not given by
  126. system, it's given by your own serialize method. So the format of data is
  127. designed by yourself, and deserialize it here as you serialize it in
  128. "serialize" method.
  129. '''
  130. def deserialize(self, data):
  131. if not data:
  132. return
  133. nodes = data.split(',')
  134. root = TreeNode(int(nodes[0]))
  135. i = 1
  136. queue = collections.deque()
  137. queue.append(root)
  138. while queue:
  139. node = queue.popleft()
  140. if nodes[i] == '#':
  141. node.left = None
  142. else:
  143. t = TreeNode(int(nodes[i]))
  144. node.left = t
  145. queue.append(t)
  146. i += 1
  147. if nodes[i] == '#':
  148. node.right = None
  149. else:
  150. t = TreeNode(int(nodes[i]))
  151. node.right = t
  152. queue.append(t)
  153. i += 1
  154. return root

源码分析

第零种解法是后序遍历(推荐), 在serialize的时候, 需要先左->右->中。 在deserialize的时候,因为是从最后一个值开始pop, 构成tree的时候, 就应该先中->右->左。

第一种解法是前序遍历, 其中巧妙的利用了python的closure, 在serialize中, 利用了list mutable 的特性, 修改了ret中的值。 deserialize中, 利用了self.i来储存instance variable

第二种解法是广度遍历。 在deserialize的时候, 保持一个index i,记录用过的node。

Java

  1. /**
  2. * Definition of TreeNode:
  3. * public class TreeNode {
  4. * public int val;
  5. * public TreeNode left, right;
  6. * public TreeNode(int val) {
  7. * this.val = val;
  8. * this.left = this.right = null;
  9. * }
  10. * }
  11. */
  12. class Solution {
  13. /**
  14. * This method will be invoked first, you should design your own algorithm
  15. * to serialize a binary tree which denote by a root node to a string which
  16. * can be easily deserialized by your own "deserialize" method later.
  17. */
  18. public String serialize(TreeNode root) {
  19. StringBuilder sb = new StringBuilder();
  20. if (root == null) return sb.toString();
  21. seriaHelper(root, sb);
  22. return sb.substring(0, sb.length() - 1);
  23. }
  24. private void seriaHelper(TreeNode root, StringBuilder sb) {
  25. if (root == null) {
  26. sb.append("#,");
  27. } else {
  28. sb.append(root.val).append(",");
  29. seriaHelper(root.left, sb);
  30. seriaHelper(root.right, sb);
  31. }
  32. }
  33. /**
  34. * This method will be invoked second, the argument data is what exactly
  35. * you serialized at method "serialize", that means the data is not given by
  36. * system, it's given by your own serialize method. So the format of data is
  37. * designed by yourself, and deserialize it here as you serialize it in
  38. * "serialize" method.
  39. */
  40. public TreeNode deserialize(String data) {
  41. if (data == null || data.length() == 0) return null;
  42. StringTokenizer st = new StringTokenizer(data, ",");
  43. return deseriaHelper(st);
  44. }
  45. private TreeNode deseriaHelper(StringTokenizer st) {
  46. if (!st.hasMoreTokens()) return null;
  47. String val = st.nextToken();
  48. if (val.equals("#")) {
  49. return null;
  50. }
  51. TreeNode root = new TreeNode(Integer.parseInt(val));
  52. root.left = deseriaHelper(st);
  53. root.right = deseriaHelper(st);
  54. return root;
  55. }
  56. }

源码分析

由二叉树序列化的过程不难,难就难在根据字符串进行反序列化,这里引入了 Java 中的 StringTokenizer 字符串分割工具,非常方便,使得递归得以顺利实现。其中deseriaHelper的实现较为巧妙。

复杂度分析

Reference