Design an algorithm and write code to serialize and deserialize a binary tree. Writing the tree to a file is called ‘serialization’ and reading back from the file to reconstruct the exact same binary tree is ‘deserialization’.
Being able to store a binary tree to a file presents lots of benefits. First, we are able to save the binary tree to a file and restore it at a later time. We are also able to transmit the binary tree representation via network and load it into another computer. Without doubt, serialization/deserialization of a binary tree is important and an algorithm to represent a binary tree in a compact way is very desirable.
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be “resurrected” later in the same or another computer environment.Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be “resurrected” later in the same or another computer environment.
Hint:
If you have not read my previous article about Saving a Binary Search Tree to a File, you should read it now. Since we are dealing with a binary tree, not a binary search tree (BST), our previous method will not work. However, this will get you started.
Solution:
Our previous method will not work in the case of Binary Tree, because binary trees are not bound with the same rule as BST. In order for the nodes to be inserted at the correct place, we would need to output the NULL nodes using some kind of sentinel (Here, we use ‘#‘ as the sentinel) as we are doing pre-order traversal.
Assume we have a binary tree below:
_30_ / \ 10 20 / / \ 50 45 35
Using pre-order traversal, the algorithm should write the following to a file:
30 10 50 # # # 20 45 # # 35 # #
The pre-order traversal code below does all the job to serialize a binary tree, believe it or not!
void writeBinaryTree(BinaryTree *p, ostream &out) {
if (!p) {
out << "# ";
} else {
out << p->data << " ";
writeBinaryTree(p->left, out);
writeBinaryTree(p->right, out);
}
}
Deserializing a Binary Tree:
Reading the binary tree from the file is similar. We read tokens one at a time using pre-order traversal. If the token is a sentinel, we ignore it. If the token is a number, we insert it to the current node, and traverse to its left child, then its right child.
void readBinaryTree(BinaryTree *&p, ifstream &fin) {
int token;
bool isNumber;
if (!readNextToken(token, fin, isNumber))
return;
if (isNumber) {
p = new BinaryTree(token);
readBinaryTree(p->left, fin);
readBinaryTree(p->right, fin);
}
}
Alternative Solution:
We may also use level-order traversal to write/read binary tree. Level-order traversal works because like pre-order traversal, we see the parent node before its child nodes. The implementation of it using level-order traversal is left as an exercise to the reader. Read my post: Printing a Binary Tree in Level Order on how to traverse a binary tree in level-order.
Further Thoughts:
There is an obvious shortcoming in this method, that is: a sentinel is required to represent empty nodes. What if we need to store strings that can contain any characters (including the sentinel) in the binary tree? Could you come up with a solution to overcome this shortcoming?
Please note that this is not the only way to serialize a binary tree, and also probably not the most compact way. But this is good enough for a standard interview question. If you would like to explore deeper, and even apply serialization/deserialization to general trees, you may read the Binary Tree article’s encoding section on Wikipedia.
http://www.leetcode.com/2010/09/serializationdeserialization-of-binary.html