↑ ↓ to move · enter to open

018 · Advanced · Traversal, encoding

serialize a tree

A tree in memory is nodes and pointers. To save it to a file or send it over a network you flatten it into a string, and later rebuild the same tree from that string. A preorder walk that writes # for every empty child does both jobs in one pass each.

LAB 1

serialize: walk and write

Visit a node, write its value, then serialize its left subtree and its right subtree. Whenever the walk reaches an empty child, write #. Each call adds exactly one token to the output, and the dashed squares on the drawing are the empty child slots waiting for their #.

preorder
written so far
Tree

How to read this: The walk visits each node top-down, left before right, and writes what it sees into the row below. Each small # square is an empty spot that also gets written.

  • solid amber: being written now
  • amber outline: waiting for its children to finish
  • green: done
  • faint square: empty spot not reached yet

Try this: Pick Left chain and count the # marks: always one more than the number of nodes.

0
Tokens written
0
Nodes n
0
# markers · n + 1
0
String length (chars)

This stepdepth 0

The codeO(n) time · O(height) stack


        

Why 2n + 1 tokens

tokens = n values + (n + 1) markers = 2n + 1

Each of the n nodes has two child slots, 2n slots in all. Every node except the root sits in exactly one slot of its parent, so n − 1 slots hold nodes and the other n + 1 are empty. Each empty slot writes one #.

The markers tell a reader where every subtree stops. Without them the string 1,2,3 fits five different trees, as Lab 3 shows.

LAB 2

deserialize: read and rebuild

Reading runs the same recursion. A pointer moves left to right through the tokens. A number makes a node and then builds its left and right children, and a # returns an empty child. Edit the string to see how a broken one fails. The call stack is the same idea as in 005 · Recursion & fractals.

rebuild
input
Try

How to read this: The highlighted token is where the reader is. Each number makes a node; each # closes an empty spot. Red marks where a broken string fails.

  • amber token: being read now
  • small number under a token: its position
  • red ?: the tree needed another token here
  • red tokens: leftover or unreadable
  • all gold: finished, valid tree

Try this: Press Too few and Too many and watch where the red appears.

0
Pointer i / tokens
0
Nodes built
0
Stack depth
—
Status

This stepdepth 0

The codei is shared by every call


        

Round trip—

Each call consumes exactly one token and recurses in the same order the writer did, so the reader stops at the same boundaries the writer marked. A string is valid exactly when the root's call returns on the last token. Running out first means too few tokens, and leftovers mean too many.

LAB 3

formats compared

Tree A is your tree. Tree B has a different shape but the same preorder sequence of values, so preorder alone cannot tell them apart. The null markers, the level order and the inorder sequence all can. Step through B to watch preorder plus inorder pin down one tree.

Tree A
Tree B
Rebuild

How to read this: Both trees list their values in the same order top-down, yet have different shapes. The tree with the green title is the one being rebuilt step by step.

0
Trees with this preorder
—
Shape shown as B
0
Nodes n
0
Rebuild step

Rebuild from preorder + inordertree B

preorder
inorder
  • amber: the current root
  • green outline: values in its left branch
  • white outline: values in its right branch
  • faded: not part of this branch

Why the pair works

shapes with n nodes = C(n) = (2n)! / ((n+1)! · n!)

Label any shape in preorder with the same values and its preorder comes out identical, so a bare preorder list fits C(n) trees: 1, 2, 5, 14, 42, 132, 429 for n = 1 to 7.

Preorder names each subtree's root first. Inorder lists everything left of that root before it and everything right of it after. With distinct values the root appears once in the inorder slice, so every split is forced. With repeats it breaks: 1,1 is both the preorder and the inorder of a root with a left child, and of a root with a right child.

Level order with nulls is the format LeetCode uses. It walks the tree breadth first, as in 002 · Graphs, and trims the nulls at the end. It is short for bushy trees and long for chains.