Trees · Binary Tree Views

Binary Tree Vertical Ordering

Tracking each node's horizontal distance from the root (left child: -1, right child: +1) during a BFS pass, then grouping nodes into columns by that distance and ordering each column top-to-bottom.

  • 7 min read
  • 9 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: when order inside a column doesn't matter
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Vertical ordering reads a tree in columns, as if it were drawn on paper and sliced vertically. Every node gets two coordinates. Its column is one left of its parent for a left child and one right for a right child. Its row is its level. The answer groups nodes by column, from left to right, and top to bottom within each column. Top and bottom views keep one node per column; vertical order keeps them all.

We'll go from simple to more technical:

  1. The pattern: BFS assigning columns and rows, then grouping.
  2. A second flavor: when order inside a column doesn't matter (vertical sums).
  3. Where giving every node a 2D position is needed.
  4. The coordinate bugs, tie-breaking, and map ordering.

The approach

The root is in column 0, row 0. A left child sits one column to the left of its parent, a right child one column to the right, and both one row down. Walk the tree with BFS, give every node its column and row, and add it to a list for its column.

right

5

3

9

1

4

12

right

5

3

9

1

4

12

NodeColumnRow
500
3-11
9+11
1-22
40 (3's right child)2
12+22

Read left to right, the columns are [1], [3], [5, 4], [9] and [12]. The top view keeps the first node in each column: 1, 3, 5, 9, 12. The bottom view keeps the last: 1, 3, 4, 9, 12.

Java

// BFS carrying (node, hd, level); a TreeMap keeps the columns sorted by hd
TreeMap<Integer, List<int[]>> columns = new TreeMap<>();      // hd -> list of {level, val}
Queue<Object[]> queue = new ArrayDeque<>();
if (root != null) queue.offer(new Object[]{root, 0, 0});
while (!queue.isEmpty()) {
    Object[] e = queue.poll();
    TreeNode node = (TreeNode) e[0];
    int hd = (int) e[1], level = (int) e[2];
    columns.computeIfAbsent(hd, k -> new ArrayList<>()).add(new int[]{level, node.val});
    if (node.left != null)  queue.offer(new Object[]{node.left,  hd - 1, level + 1});
    if (node.right != null) queue.offer(new Object[]{node.right, hd + 1, level + 1});
}
for (List<int[]> col : columns.values())
    col.sort((a, b) -> a[0] != b[0] ? Integer.compare(a[0], b[0]) : Integer.compare(a[1], b[1]));  // level, then value

Python

from collections import defaultdict, deque

# BFS carrying (node, hd, level); Python has no TreeMap - sort the column keys at the end
columns = defaultdict(list)                     # hd -> list of (level, val)
queue = deque([(root, 0, 0)] if root else [])
while queue:
    node, hd, level = queue.popleft()
    columns[hd].append((level, node.val))
    if node.left:
        queue.append((node.left, hd - 1, level + 1))
    if node.right:
        queue.append((node.right, hd + 1, level + 1))
result = [[val for _, val in sorted(columns[hd])] for hd in sorted(columns)]   # level, then value

hd stands for horizontal distance, the column. The TreeMap returns the columns left to right. BFS visits level by level, so each column's list is already top to bottom. The sort is there for ties: two nodes can share a column and a row, and the problem then orders them by value. For the top view, keep only the first node per column (putIfAbsent); for the bottom view, the last (put, overwriting).

A second flavor: when order inside a column doesn't matter

The vertical sum of each column doesn't depend on the order its nodes arrive in. So there's nothing to sort, and no need for a TreeMap either. In the tree above, the sums are 1, 3, 9, 9 and 12 (column 0 adds 5 and 4).

Java

Map<Integer, Long> sums = new HashMap<>();
int minHd = 0, maxHd = 0;
void walk(TreeNode node, int hd) {
    if (node == null) return;
    sums.merge(hd, (long) node.val, Long::sum);
    minHd = Math.min(minHd, hd);
    maxHd = Math.max(maxHd, hd);
    walk(node.left, hd - 1);
    walk(node.right, hd + 1);
}
// then emit sums.get(hd) for hd = minHd .. maxHd

Python

def vertical_sum(root: TreeNode) -> list[int]:
    sums = {}
    lo = hi = 0

    def walk(node: TreeNode | None, hd: int) -> None:
        nonlocal lo, hi
        if node is None:
            return
        sums[hd] = sums.get(hd, 0) + node.val
        lo, hi = min(lo, hd), max(hi, hd)
        walk(node.left, hd - 1)
        walk(node.right, hd + 1)

    walk(root, 0)
    return [sums[hd] for hd in range(lo, hi + 1)]   # every column in lo..hi is non-empty

Any traversal works, even DFS. To list the columns in order, count from the smallest column to the largest. Every column in that range has a node, because each edge moves exactly one column. That makes it O(n) instead of O(n log n).

Where you'll see it

Drawing a tree as a diagram, such as a family tree or a syntax tree in a debugger, needs these columns before anything can be placed.

Which tool for which job?

You needUse
All nodes per column, top to bottomBFS with (column, row), sort ties by value
One node per column (top or bottom view)BFS, keep the first or last per column
A total per column (vertical sum)any traversal - order doesn't matter
Columns in order without a sorted maptrack min and max column; index a list by col - min

Common mistakes

MistakeWhat happensDo this instead
DFS order taken as top-to-bottoma column comes out out of orderrecord the row and sort by it, or use BFS
No rule for same-row, same-column tiesnon-deterministic outputbreak ties (by value, as the problem says)
Iterating a HashMap or a dict for columnscolumns out of orderTreeMap, sorted keys, or a min..max range
Confusing a view with vertical orderone node per column instead of allread which output is asked
Sorting when only sums are neededwasted O(n log n)aggregate in any order

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. In [1, 2, 3, 4, 5, 6, 7], which nodes are in column 0, and why do two of them need a tie-break?

Show answer

1 (row 0), plus 5 and 6 (both row 2). 5 is 2's right child, -1 + 1 = 0, and 6 is 3's left child, +1 - 1 = 0. They share a column and a row, so "top to bottom" can't order them. The problem's tie-break, by value, does.

2. Why can the vertical sum use a HashMap and skip sorting, when vertical order can't?

Show answer

A sum doesn't depend on the order of its parts, and the columns come out in order by counting from the smallest to the largest. Vertical order must list nodes in a set order, which needs the sort.

3. A top view keeps the first node a preorder DFS reaches in each column. Give a tree where that's wrong.

Show answer

Root 1 has left child 2 and right child 3. Node 2 has a right child 4, and 4 has a right child 5. Node 5 is in column +1 at row 3; node 3 is in column +1 at row 1. Preorder reaches 5 first, so DFS reports 5, but from above you'd see 3. Use BFS, or keep the smallest row per column.

Key takeaways

  • Each node needs two coordinates: its column and its row.
  • A TreeMap by column gives left-to-right order, and BFS gives top-to-bottom order. Sort only for nodes sharing a column and a row.
  • Top and bottom views keep one node per column; vertical order keeps them all.
  • A column sum needs no sorting: a HashMap plus the smallest and largest column is O(n).
  • Never read columns straight out of a HashMap, and never treat DFS order as top to bottom.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Vertical orderBFS (col, row) + tie-break
Top / bottom viewfirst / last per column
Vertical sumany traversal
Columns in ordermin..max list

Snippets worth knowing by heart

Java

Map<Integer, List<int[]>> cols = new TreeMap<>();          // or a list offset by the min column
Deque<Object[]> q = new ArrayDeque<>(List.of(new Object[] {root, 0, 0}));
while (!q.isEmpty()) {
    Object[] e = q.poll();
    TreeNode n = (TreeNode) e[0]; int col = (int) e[1], row = (int) e[2];
    cols.computeIfAbsent(col, k -> new ArrayList<>()).add(new int[] {row, n.val});
    if (n.left != null) q.add(new Object[] {n.left, col - 1, row + 1});
    if (n.right != null) q.add(new Object[] {n.right, col + 1, row + 1});
}
// per column: sort by (row, value), then take the values

Python

from collections import defaultdict
sums = defaultdict(int)
def dfs(node, col):
    if node:
        sums[col] += node.val            # order doesn't matter for a sum
        dfs(node.left, col - 1)
        dfs(node.right, col + 1)
dfs(root, 0)
answer = [sums[c] for c in range(min(sums), max(sums) + 1)]   # columns are contiguous

The traps

  • DFS order as top-to-bottom: a column comes out of order. Record each node's row and sort by it, or use BFS.
  • No tie-break: nodes sharing a row and column print in any order. Break ties the way the problem says.
  • Hash map iteration: a HashMap or dict doesn't keep columns in order. Use a TreeMap, sorted keys or a min..max range.
  • View vs vertical order: a view keeps one node per column, vertical order keeps all. Read which one is asked.
  • Sorting for sums: column sums don't need any order, so sorting wastes O(n log n). Aggregate in any order.

Staff-level points, one line each

  • Columns are always contiguous - a min..max list replaces a TreeMap.
  • 413 of 500 random trees had same-row, same-column ties.
  • HashMap keys 0, -1, 1, -2, 2, -3 iterated unsorted; TreeMap sorted.
  • Python dicts iterate in insertion order, not key order.
  • Only ties need sorting; views and sums are O(n).

Say it in an interview

  • "Each node gets a column - left is minus one, right plus one - and a row."
  • "BFS gives rows in order; I only sort nodes tied on row and column."
  • "Columns form a contiguous range, so I can index a list by column minus the minimum."
  • "For a vertical sum, order doesn't matter, so no sorting."

Practice

This skill comes with 9 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Binary Tree Vertical Ordering free

Vertical Sum of a Binary Tree

MediumProCoding problemJava · Python

Given the root of a binary tree, return the sum of the node values in each vertical column, ordered left to right. The root is in column 0; a left child is one column to the left of its parent (-1), a right child one column to the right (+1).

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Vertical Order Traversal of a Binary Tree

HardProCoding problemJava · Python

Given the root of a binary tree, return its vertical order traversal: group nodes by horizontal distance from the root (left child: -1, right child: +1), ordered left to right by distance; within a column, order top to bottom by level, breaking ties at the same level by value…

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Binary Tree Vertical Ordering free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime