Skip to the notes
JSGroundwork
JSGroundwork handwritten · web dev
✎Playground→⌘Problems↻Review🔥Progress

Chapters

34 chapters
⌕
Beginner10›
B1Complexity analysisB2Arrays & stringsB3HashingB4Two pointersB5Sliding windowB6Binary searchB7Sorting algorithmsB8Stacks & queuesB9Linked listsB10Basic recursion
Intermediate12›
I1TreesI2Tree problems in depthI3Heaps & priority queuesI4Graphs: representationI5Graph problemsI6BacktrackingI7DP: 1DI8DP: 2DI9Greedy algorithmsI10IntervalsI11Bit manipulationI12Matrix problems
Advanced12›
A1Advanced DPA2Union-FindA3Advanced graph algorithmsA4Minimum Spanning TreeA5TriesA6Segment & Fenwick treesA7String algorithmsA8Monotonic stack & queueA9Design problemsA10Advanced backtrackingA11Topological patternsA12Interview strategy
/ search[ ] chaptert top

DSA in JS levels

1Beginner2Intermediate3Advanced

Ready to read

JSJavaScript⑂Git◎Interview prepΣDSA in JSSDSystem Design
More topics15›
</>HTML{ }CSS⚛ReactNNext.jsNeNest.jsTSTypeScriptNoNode.js🐳DockerDBSQL & Databases✓Testing🔒Web Security☁Cloud & DevOps◈GraphQL◆Redis☸Kubernetes
100%
I1

Trees

A linked list that's allowed to branch — and the three orders you can walk it in.

What makes something a tree

A tree is a linked structure with one rule a linked list doesn't have: each node can point to more than one child, and there are no cycles — you can never walk from a node back to itself. That single branching rule is what unlocks a completely different family of algorithms from the linear ones you just spent the beginner tier on.

8 3 10 1 6 14 root green = leaves (no children) · height = 2 (root → leaf, in edges)
3 and 10 are children of 8, and parents of the leaves below them — the same node wears both hats.

Vocabulary you need cold

TermMeans
Rootthe top node, the only one with no parent
Leafa node with no children
Heightthe number of edges on the longest root-to-leaf path
Depththe number of edges from the root to that specific node
Balancedfor every node, the left and right subtree heights differ by at most 1
Binary Search Tree (BST)a binary tree where every left subtree is smaller, every right subtree is bigger

The BST property, drawn

everything here is < 8 8 everything here is > 8
This must hold at every node, not just the root — that's what makes binary search work on it.

This property is the entire reason BST search is O(log n) on a balanced tree — same idea as binary search on a sorted array, just implemented as pointers instead of index math: compare, then throw away half the tree.

function bstSearch(node, target) {
  if (node === null) return null;
  if (node.val === target) return node;
  return target < node.val
    ? bstSearch(node.left, target)
    : bstSearch(node.right, target);
}
⚠ "BST" only buys you O(log n) if it's balanced Insert 1,2,3,4,5 in order into a BST with no rebalancing and you get a straight line, not a tree — every operation degrades to O(n), same as a linked list. This is exactly why self-balancing trees (AVL, red-black) exist, even though you'll rarely implement one by hand in an interview.

The three depth-first traversal orders

All three visit every node exactly once and all three use the same recursive shape — the only difference is where you place the "visit this node" line relative to the two recursive calls.

2nd 1st 3rd 1st 2nd 3rd 3rd 1st 2nd In-order Pre-order Post-order In-order: left, node, right — sorted output on a BST Pre-order: node, left, right — good for copying a tree Post-order: left, right, node — good for deleting a tree
Same tree, same recursive shape — only the position of "visit node" relative to the two recursive calls changes.
function inOrder(node, out = []) {
  if (node === null) return out;
  inOrder(node.left, out);
  out.push(node.val);   // visit AFTER left, BEFORE right
  inOrder(node.right, out);
  return out;
}

function preOrder(node, out = []) {
  if (node === null) return out;
  out.push(node.val);   // visit FIRST
  preOrder(node.left, out);
  preOrder(node.right, out);
  return out;
}

function postOrder(node, out = []) {
  if (node === null) return out;
  postOrder(node.left, out);
  postOrder(node.right, out);
  out.push(node.val);   // visit LAST
  return out;
}
Say it like this → "In-order traversal of a BST always produces sorted output, because at every node you visit everything smaller (left) before the node itself, before everything bigger (right) — that ordering guarantee is exactly the BST property applied recursively."

Breadth-first (level-order) — the one traversal that isn't depth-first

All three orders above dive to the bottom before coming back up. Level order does the opposite: visit every node at depth 0, then every node at depth 1, then depth 2 — this needs a queue, not recursion, because you have to remember an entire "frontier" of nodes at once.

function levelOrder(root) {
  if (root === null) return [];
  const result = [];
  const queue = [root];
  while (queue.length) {
    const levelSize = queue.length; // freeze how many belong to THIS level
    const level = [];
    for (let i = 0; i < levelSize; i++) {
      const node = queue.shift();
      level.push(node.val);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    result.push(level);
  }
  return result;
}

The levelSize snapshot is the trick — without it you can't tell where one level ends and the next begins, since the queue just keeps growing as you go.

Doing it without recursion — a near-guaranteed follow-up

"Can you do that iteratively?" is one of the most common tree follow-up questions, because it tests whether you actually understand what recursion was doing for you (managing a stack of "come back to this later" positions) rather than just pattern-matching the recursive shape.

// iterative pre-order — the easiest one: an explicit stack, push right before left
function preOrderIterative(root) {
  if (root === null) return [];
  const result = [];
  const stack = [root];
  while (stack.length) {
    const node = stack.pop();
    result.push(node.val);
    if (node.right) stack.push(node.right); // push right FIRST
    if (node.left) stack.push(node.left);   // so left gets popped first
  }
  return result;
}

// iterative in-order — trickier: walk left as far as possible, THEN visit, THEN go right
function inOrderIterative(root) {
  const result = [];
  const stack = [];
  let curr = root;
  while (curr !== null || stack.length) {
    while (curr !== null) {   // go as far left as possible, remembering the path
      stack.push(curr);
      curr = curr.left;
    }
    curr = stack.pop();        // backtrack to the last unvisited node
    result.push(curr.val);
    curr = curr.right;         // then explore its right subtree
  }
  return result;
}

Post-order iteratively is the fiddly one — the cleanest trick is to compute pre-order but visiting right before left (swap the push order above), collect that into a list, then reverse it. Right-Node-Left reversed is exactly Left-Right-Node, which is post-order — worth remembering as a shortcut rather than deriving a true post-order stack machine from scratch under interview pressure.

Say it like this → "Recursion was implicitly using the call stack to remember 'come back to this node later' — I can make that explicit with my own stack and get the identical traversal order without the recursive call overhead."

Complexity — the numbers to state out loud

OperationBalanced BSTUnbalanced (worst case)
Search / insert / deleteO(log n)O(n)
Any traversal (visits every node once)O(n)O(n)
Space (recursive call stack)O(log n) — height of the treeO(n)
Space (level order, via queue)O(n) — widest level, up to n/2 nodesO(n)

Recognizing it in an unseen problem

  • The input is described as a "binary tree" or "BST" with .left/.right
  • "Sorted order" out of a BST → in-order is almost always the answer
  • "Level by level" or "shortest path in an unweighted tree" → level order (BFS)
  • "Build/copy/serialize" → pre-order; "safely delete/free" → post-order
Practice this layer

Opens in the editor — write it, run it, and check it against real tests.

Maximum Depth of Binary Tree5 tests · beginnerSame Tree5 tests · beginnerSymmetric Tree5 tests · beginnerInvert Binary Tree5 tests · beginnerBinary Tree Level Order Traversal5 tests · beginnerPath Sum5 tests · beginner
←previousBasic recursion↑ CovernextTree problems in depth→