I went to an interview today where I was asked to serialize a binary tree. I implemented an array-based approach where the children of node i (numbering in level-order trave
I am not using pre-order but I am using BFS. This is a question from leetcode
Majority of people implementation are incorrect when using pre-order: the expected result should be
"[1,2,3,null,null,4,5]", but instead majority people print the output as "[1,2,3,null,null,4,5,null,null]" since they are not counting the levels.
Here is my implementation with the correct result.
class Node(object):
def __init__(self,data):
self.left = None
self.right = None
self.data = data
def serialize(root):
queue = [(root,0)]
result = []
max_level_with_value = 0
while queue:
(node,l) = queue.pop(0)
if node:
result.append((node.data,l))
queue.extend([(node.left,l+1),
(node.right,l+1)
])
max_level_with_value = max(max_level_with_value,l)
else:
result.append(('null',l))
filter_redundant(result,max_level_with_value)
def filter_redundant(result,max_level_with_value):
for v,l in result:
if l<= max_level_with_value:
print(v)
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.right.left = Node(4)
root.right.right = Node(5)
serialize(root)
convert it to array with size of (2n + 1) each left son and right son will be in place of (2 * node number) and ((2 * node number) + 1 accordingly.
using https://www-inst.eecs.berkeley.edu//~cs61bl/r/cur/trees/array-repr.html?topic=lab20.topic&step=1&course=
All those articles talk mostly about the serialization part. The deserialization part is slightly tricky to do in one pass.
I have implemented an efficient solution for deserialization too.
Problem: Serialize and Deserialize a binary tree containing positive numbers.
Serialization part:
Deserialization part:
Below is the code in Java:
public final class BinaryTreeSerializer
{
public static List<Integer> Serialize(BTNode root)
{
List<Integer> serializedNums = new ArrayList<Integer>();
SerializeRecursively(root, serializedNums);
return serializedNums;
}
private static void SerializeRecursively(BTNode node, List<Integer> nums)
{
if (node == null)
{
nums.add(0);
return;
}
nums.add(node.data);
SerializeRecursively(node.left, nums);
SerializeRecursively(node.right, nums);
}
public static BTNode Deserialize(List<Integer> serializedNums)
{
Pair pair = DeserializeRecursively(serializedNums, 0);
return pair.node;
}
private static Pair DeserializeRecursively(List<Integer> serializedNums, int start)
{
int num = serializedNums.get(start);
if (num == 0)
{
return new Pair(null, start + 1);
}
BTNode node = new BTNode(num);
Pair p1 = DeserializeRecursively(serializedNums, start + 1);
node.left = p1.node;
Pair p2 = DeserializeRecursively(serializedNums, p1.startIndex);
node.right = p2.node;
return new Pair(node, p2.startIndex);
}
private static final class Pair
{
BTNode node;
int startIndex;
private Pair(BTNode node, int index)
{
this.node = node;
this.startIndex = index;
}
}
}
public class BTNode
{
public int data;
public BTNode left;
public BTNode right;
public BTNode(int data)
{
this.data = data;
}
}
The best way is to use a special char (like # as previous comment mentioned) as sentinel. It's better than constructing an inorder traversal array and a preorder/postorder traversal array, both in space complexity wise and time complexity wise. it's also way easier to implement.
Linked list is not a good fit here since in order to reconstruct the tree, you better have const element access time
Here is a late answer in Python. It uses (depth-first) preorder serialization and returns a list of strings
. Deserialization returns the tree.
class Node:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
# This method serializes the tree into a string
def serialize(root):
vals = []
def encode(node):
vals.append(str(node.val))
if node.left is not None:
encode(node.left)
else:
vals.append("L")
if node.right is not None:
encode(node.right)
else:
vals.append("R")
encode(root)
print(vals)
return vals
# This method deserializes the string back into the tree
def deserialize(string_list):
def create_a_tree(sub_list):
if sub_list[0] == 'L' or sub_list[0] == 'R':
del sub_list[0]
return None
parent = Node(sub_list[0])
del sub_list[0]
parent.left = create_a_tree(sub_list)
parent.right = create_a_tree(sub_list)
return parent
if len(string_list) != 0:
root_node = create_a_tree(string_list)
else:
print("ERROR - empty string!")
return 0
return root_node
To test:
tree1 = Node('root', Node('left'), Node('right'))
t = deserialize(serialize(tree1))
print(str(t.right.val))
How about performing an in-order traversal and putting the root key and all node keys into a std::list or other container of your choice which flattens the tree. Then, simply serialize the std::list or container of your choice using the boost library.
The reverse is simple and then rebuild the tree using standard insertion to a binary tree. This may not be entirely efficient for a very large tree but runtime to convert the tree into a std::list is O(n) at most and to rebuild the tree is O(log n) at most.
I am about to do this to serialize a tree I just coded up in c++ as I am converting my database from Java to C++.