The short answer

Serialization flattens a binary tree into a storable string, usually by walking it in pre-order or level-order and writing a marker such as # for every empty child. Deserialization is the exact inverse: it reads that string back and rebuilds the identical tree. In short, serialize turns a tree into text for storage or transfer, and deserialize turns the text back into a tree.

Serializing and deserializing a binary tree is a classic data-structures problem, and it is LeetCode 297 in interviews. Managing tree structures efficiently requires understanding both operations. One converts a tree into a portable format, while the other reconstructs it from that format.

The core idea is that the two are inverses. Serialization bridges an in-memory structure and its persistent form, whereas deserialization breathes life back into the hierarchy. This guide defines each operation, shows the code and the null-marker trick, compares them in detail, and explains when each matters.

If you are still mapping out tree basics, it helps to know the difference between a binary tree and a binary search tree first.

Diagram of a five-node binary tree on the left converted by a serialize arrow into the string 1,2,#,#,3,4,5 on the right, with a deserialize arrow pointing back to the tree
Serialize turns the tree into a string; deserialize rebuilds the tree from it.

What is Serialization?

Binary tree serialization transforms a tree into a compact, portable format, usually a string. That flat form is easy to store in a file, save in a database, or send over a network. So serialization is the bridge between an in-memory data structure and its persistent or transferable counterpart.

The method is a traversal. You walk the tree in a fixed order, writing each node’s value as you go, and you write a marker such as # or null whenever a child is missing. Those markers are essential, because they record the tree’s shape, not just its values.

Advantages of serialization:

  • Produces a compact string that is easy to store or transmit.
  • Straightforward to implement, since it is a linear traversal.
  • Preserves the exact structure when null markers are included.
  • Language-neutral, so any system can read the format.

Disadvantages of serialization:

  • Null markers add extra characters, so the string grows.
  • The format must be agreed in advance by both sides.

What is Deserialization?

Binary tree deserialization is the reverse: it reconstructs the tree from its serialized form. This is the operation you run when retrieving stored data or receiving it over a network, and it restores the full hierarchical structure.

Deserialization usually uses recursion. The algorithm descends through the serialized string, consuming one token at a time and building nodes as it goes. When it meets a null marker, it returns nothing, which correctly leaves that child empty. The process continues until the whole string is consumed.

Advantages of deserialization:

  • Restores the exact original tree, node for node.
  • Recursion keeps the algorithm short and readable.
  • Runs in linear time when the format includes null markers.

Disadvantages of deserialization:

  • Recursive descent uses stack space, which deep trees can strain.
  • It fails if the format or the markers do not match the writer.

Serialize vs Deserialize: Comparison Table

Grid comparing serialize and deserialize on input tree versus string, output string versus tree, direction flatten versus rebuild, and needs traversal versus null markers
Serialize vs deserialize at a glance: input, output, direction, and what each needs.
AspectSerializeDeserialize
PurposeConvert a tree into a storable formatRebuild the tree from that format
InputBinary tree (in memory)String or byte stream
OutputString or byte streamBinary tree (in memory)
DirectionFlatten (tree to text)Rebuild (text to tree)
Core techniqueTraversal (pre-order or level-order)Recursion or a queue, in the same order
Null handlingWrites a marker such as # for empty childrenReads the marker and leaves that child empty
Time complexityO(n), visits each node onceO(n), consumes each token once
Space complexityO(n) for the output stringO(n) for the tree, plus O(h) call stack
Typical useSaving, caching, or sending a treeLoading or receiving a tree
Order of operationsRuns first, before storage or transferRuns second, after retrieval
Main riskLosing shape if markers are omittedCorrupt output if the format mismatches
RelationshipExact inverses: deserialize(serialize(tree)) returns the same tree

Traversal Orders and Null Markers

 Two trees each with one child, one on the left and one on the right, showing different serialized strings because the null markers record which side is missing
Null markers are what tell the two shapes apart in the string.

The traversal order decides the format, so both sides must use the same one.

Pre-order visits the root first, then the left subtree, then the right. It is the most common choice, because the root arrives first, so a recursive rebuild can create each node before its children. Post-order visits the left and right subtrees before the root, and it also rebuilds uniquely, though you read the string in reverse and build the right child before the left. Level-order, or breadth-first, writes the tree row by row using a queue, which is the format LeetCode shows.

In-order is the exception. An in-order sequence alone cannot rebuild a binary tree, because many different trees produce the same in-order output. So in-order only works when it is paired with a pre-order or post-order sequence, which is a separate classic problem.

Null markers matter just as much. Without them, a root with only a left child and a root with only a right child would serialise to the same node list. The markers record which side is empty, so the shape survives the round trip.

Python Code

Here is the standard pre-order solution, with # as the null marker. Serialization walks the tree, and deserialization consumes the same tokens in the same order.

class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


def serialize(root):
    """Flatten a binary tree into a pre-order string."""
    out = []

    def walk(node):
        if node is None:
            out.append('#')          # null marker keeps the shape
            return
        out.append(str(node.val))
        walk(node.left)
        walk(node.right)

    walk(root)
    return ','.join(out)


def deserialize(data):
    """Rebuild the binary tree from that string."""
    tokens = iter(data.split(','))

    def build():
        token = next(tokens)
        if token == '#':
            return None
        node = Node(int(token))
        node.left = build()
        node.right = build()
        return node

    return build()


# round trip:  1 -> (2, 3), 3 -> (4, 5)
tree = Node(1, Node(2), Node(3, Node(4), Node(5)))
text = serialize(tree)
print(text)                              # 1,2,#,#,3,4,#,#,5,#,#
print(serialize(deserialize(text)) == text)   # True

Notice the symmetry. The writer appends a # for every missing child, and the reader returns None on every #. Because both sides follow the identical order, the round trip returns exactly the original tree, which the final check confirms.

When Each Matters

Serialization and deserialization always come as a pair, yet the workload decides which one you tune.

Serialization leads when data is written often: caching a tree, saving it to disk, or sending it across a network. Since it is a simple linear walk, the cost is predictable, so keeping the output compact matters most there.

Deserialization leads when data is read often, such as loading a saved structure at startup. Its recursion uses stack space, so very deep trees may need an iterative version instead. Therefore an application heavy on retrieval should watch the rebuild path more closely.

Interview Questions

Without markers, the string records only the values, not the shape. A root with a single left child and a root with a single right child would then look identical. The markers show which child is empty, so the tree can be rebuilt exactly.

Many different trees share the same in-order sequence, so the order alone is ambiguous. Pre-order and post-order avoid this because the root’s position is fixed at one end. Therefore in-order must be paired with pre-order or post-order to identify a unique tree.

Both operations run in O(n), since each node or token is handled once. Serialization uses O(n) space for the output string, while deserialization uses O(n) for the tree plus O(h) for the recursion stack, where h is the height. So a balanced tree costs O(log n) stack, and a skewed one costs O(n).

Use a level-order format with a queue, which rebuilds the tree iteratively row by row. That keeps the stack flat, so a very deep or skewed tree cannot overflow it. So the iterative BFS approach is the safer choice for large inputs.

Frequently Asked Questions

Pre-order starts with the root, then the left and right subtrees, so the root always arrives first. In-order visits the left subtree, then the root, then the right. That difference matters, because pre-order with null markers rebuilds a unique tree, while an in-order sequence alone does not.

Yes, the priority follows your workload. If storage or transmission efficiency is critical, tune the serialized format to stay compact. If your application frequently reloads and rebuilds data, focus on a fast, stack-safe deserialization instead.

The challenge is recognising the placeholders that mark a missing left or right subtree. Both the writer and the reader must agree on the marker, such as # or null. If the reader misinterprets them, the rebuilt tree takes the wrong shape.

Yes, post-order also rebuilds a tree uniquely when null markers are present. You simply read the serialized tokens in reverse and build the right child before the left, since the root sits at the end. It suits cases where children must be processed before their parent, such as evaluating an expression tree.

Recursion lets the algorithm descend through the serialized string, extracting one token at a time and building the tree as it goes. Each call creates one node and then asks for its two children, which mirrors the tree’s own shape. So the recursive approach turns a complex rebuild into a few lines.

In practice, no, and it is not advisable. The reader must know exactly which order produced the string, so mixing orders inside one output makes it ambiguous. Pick one format, such as pre-order or level-order, and use it consistently on both sides.

Wrapping Up

Serialization and deserialization are two halves of one round trip. Serialization walks a binary tree and flattens it into a string with null markers, while deserialization reads that string back and rebuilds the identical tree.

Remember the essentials: use pre-order or level-order, always write markers for empty children, and keep both sides on the same format. Both run in O(n), and in-order alone can never rebuild a tree. That is enough to answer most exam and interview questions on the pair.

Related reading on DiffStudy:


Whatsapp-color Created with Sketch.

By Arun Kumar

Full Stack Developer with a BE in Computer Science, working with React, Next.js, Node.js, MongoDB, and AI/ML tools. Founder of DiffStudy — built to help CS students ace GATE and university exams, and keep developers up to date across AI, cloud, system design, web development, and every field of computer science. Every article is written from real hands-on experience, not just theory.

Leave a Reply

Your email address will not be published. Required fields are marked *


You cannot copy content of this page